这些查询可以组合成一个吗?

时间:2017-01-15 18:26:32

标签: sql mfc jet

我有这个MFC代码从Microsoft Access数据库中提取名称列表:

// Extracts all the brothers from the specified tables into the passed in array
void CPTSDatabase::BuildBrothersArray(CStringArray &rAryStrBrothers)
{
    CWaitCursor         wait;
    CMapStringToString  mapStrBrothers;
    CStringArray        aryStrQueries, aryStrFields;
    CString             strText, strBrother;
    POSITION            sPos;
    int                 iTable, iNumTables;

    rAryStrBrothers.RemoveAll();

    if (m_dbDatabase.IsOpen())
    {
        strText.Format(_T("SELECT * FROM [Congregation Speakers] ")
                _T("WHERE [Congregation]='%s' ORDER BY Speaker"), (LPCTSTR)GetLocalCongregation());
        aryStrQueries.Add(_T("SELECT * FROM Brothers WHERE BrotherChairman=-1"));
        aryStrQueries.Add(_T("SELECT * FROM Brothers WHERE BrotherReader=-1"));
        aryStrQueries.Add(_T("SELECT * FROM Brothers WHERE BrotherConductorWT=-1"));
        aryStrQueries.Add(strText);

        aryStrFields.Add(_T("BrotherName"));
        aryStrFields.Add(_T("BrotherName"));
        aryStrFields.Add(_T("BrotherName"));
        aryStrFields.Add(_T("Speaker"));

        iNumTables = 4;
        for (iTable = 0; iTable < iNumTables; iTable++)
        {
            GetBrotherData(aryStrQueries[iTable], aryStrFields[iTable], mapStrBrothers);
        }

        sPos = mapStrBrothers.GetStartPosition();
        while (sPos != NULL)
        {
            mapStrBrothers.GetNextAssoc(sPos, strText, strBrother);
            rAryStrBrothers.Add(strBrother);
        }
    }
}

// Extracts all the brothers from the specified table / field
// A map is used so that we end up with a list of unique brothers
void CPTSDatabase::GetBrotherData(CString strSQL, CString strField,
                                  CMapStringToString &rMapBrothers)
{
    CRecordset  *pRecordset = NULL;
    CString     strBrother;

    if (!m_dbDatabase.IsOpen())
        return;

    pRecordset = new CRecordset(&m_dbDatabase);
    if (pRecordset != NULL)
    {
        pRecordset->Open(CRecordset::snapshot,(LPCTSTR)strSQL);
        while (!pRecordset->IsEOF() )
        {
            pRecordset->GetFieldValue(strField, strBrother);
            rMapBrothers.SetAt(strBrother, strBrother);
            pRecordset->MoveNext();
        }

        pRecordset->Close();
        delete pRecordset ;
    }
}

// Locates the Congregation that has the "Local" flag set
// The local congregation is the home congregation
CString CPTSDatabase::GetLocalCongregation()
{
    CRecordset  *pCongs = NULL;
    CString     strCong, strQuery;

    if (m_dbDatabase.IsOpen())
    {
        pCongs = new CRecordset( &m_dbDatabase );
        if (pCongs != NULL)
        {
            strQuery = _T("SELECT * FROM [Congregations] WHERE [Local] = 1");
            pCongs->Open( CRecordset::snapshot, (LPCTSTR)strQuery );
            if( pCongs->GetRecordCount() > 0 )
            {
                pCongs->GetFieldValue(_T("Congregations"), strCong);
            }
        }
        pCongs->Close();
        delete pCongs ;
    }

    return strCong;
}

正如您所看到的,我有几个表,我正在进行搜索并在列表中添加任何唯一的名称。我不想让任何事情过于复杂,但是可以将这个结合起来是一个查询并提取一个CRecordSet,其中包含一个唯一的名称列表吗?

更新

我做了一些研究后似乎需要一个UNION。所以我需要将这些查询的不同结果合并为一个列:

SELECT Speaker FROM [Congregation Speakers] WHERE [Congregation]='xyz'
SELECT BrotherName FROM Brothers WHERE BrotherChairman=-1")
SELECT BrotherName FROM Brothers WHERE BrotherReader=-1
SELECT BrotherName FROM Brothers WHERE BrotherConductorWT=-1

结果应按A到Z排序。

更新

我做了一些研究后似乎需要一个UNION。所以我需要将这些查询的不同结果合并为一个列:

SELECT Speaker FROM [Congregation Speakers] WHERE [Congregation]='xyz'
SELECT BrotherName FROM Brothers WHERE BrotherChairman=-1")
SELECT BrotherName FROM Brothers WHERE BrotherReader=-1
SELECT BrotherName FROM Brothers WHERE BrotherConductorWT=-1

结果应按A到Z排序。

更新

我试过了:

void CPTSDatabase::BuildBrothersArray(CStringArray &rAryStrBrothers)
{
    CWaitCursor         wait;
    CRecordset *pRecordset = nullptr;
    if (!m_dbDatabase.IsOpen())
        return;

    pRecordset = new CRecordset(&m_dbDatabase);
    if (pRecordset != nullptr)
    {
        CString strSQL = _T(""), strName = _T("");

        strSQL.Format(_T("WITH CTE(Name) AS(")
            _T("SELECT Speaker FROM [Congregation Speakers] WHERE [Congregation] = '%s' ")
            _T("UNION ")
            _T("SELECT BrotherName FROM Brothers WHERE BrotherChairman = -1 OR BrotherReader = -1 OR BrotherConductorWT = -1)")
            _T(") ")
            _T("SELECT Name FROM CTE ORDER BY Name ASC"), (LPCTSTR)GetLocalCongregation());

        try
        {
            pRecordset->Open(CRecordset::snapshot, (LPCTSTR)strSQL);
            while (!pRecordset->IsEOF())
            {

                pRecordset->GetFieldValue(_T("Name"), strName);
                rAryStrBrothers.Add(strName);
                pRecordset->MoveNext();
            }

            pRecordset->Close();
        }
        catch (CDBException* e)
        {
            TCHAR szError[_MAX_PATH];
            e->GetErrorMessage(szError, _MAX_PATH);
            AfxMessageBox(szError);

        }

        delete pRecordset;
    }
}

但是我收到了这个错误:

Error

更新2

这似乎工作正常:

strSQL.Format(_T("SELECT Speaker AS Name FROM [Congregation Speakers] WHERE [Congregation] = '%s' ")
    _T("UNION ")
    _T("SELECT BrotherName AS Name FROM Brothers WHERE BrotherChairman = -1 OR BrotherReader = -1 OR BrotherConductorWT = -1 ORDER BY Name ASC"), (LPCTSTR)GetLocalCongregation());

2 个答案:

答案 0 :(得分:2)

没有尝试过,只是快速入侵:

WITH CTE(Name) AS (
  SELECT Speaker FROM [Congregation Speakers] WHERE [Congregation]='xyz'
  UNION
  SELECT BrotherName FROM Brothers WHERE BrotherChairman=-1 OR BrotherReader=-1 OR BrotherConductorWT=-1
)
SELECT Name FROM CTE ORDER BY Name ASC

请不要从用户输出中动态编写SQL字符串,而是使用参数化查询,否则您将容易受到SQL注入攻击。

答案 1 :(得分:0)

根据原始答案,这适用于我的CRecordSet

strSQL.Format(
    _T("SELECT Speaker AS Name FROM [Congregation Speakers] WHERE [Congregation] = '%s' ")
    _T("UNION ")
    _T("SELECT BrotherName AS Name FROM Brothers WHERE ")
    _T("BrotherChairman = -1 OR ")
    _T("BrotherReader = -1 OR ")
    _T("BrotherConductorWT = -1 OR ")
    _T("BrotherHospitality = -1 OR ")
    _T("BrotherInterpreter = -1 OR ")
    _T("BrotherMiscellaneous = -1 ")
    _T("ORDER BY Name ASC"), (LPCTSTR)GetLocalCongregation());