I have this MFC code to extract a list of names from a Microsoft Access Database:
// 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;
}
As you can see, I have several tables where I am doing searches and added any unique names to a list. I don't want to overcomplicate anything but is it possible to combine this is a single query and pull out one CRecordSet
that has one unique list of names?
Having done a bit more research it seems I need a UNION. So I need to combine the distinct results from these queries as a single column:
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
The results should be sorted A to Z.
Having done a bit more research it seems I need a UNION. So I need to combine the distinct results from these queries as a single column:
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
The results should be sorted A to Z.
I have tried:
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;
}
}
But I get this error:
This seems to work fine:
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());
Based on the original answer, this is what works for my 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());