这些查询可以合并为一个吗?
Can these queries be combined into one?
我有这个 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;
}
}
但是我得到这个错误:
更新 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());
没试过,很快就破解了:
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 注入攻击。
根据原始答案,这对我的 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());
我有这个 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;
}
}
但是我得到这个错误:
更新 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());
没试过,很快就破解了:
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 注入攻击。
根据原始答案,这对我的 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());