我需要构建一个SQL查询来读取Excel文件,通过ODBC与Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)
。
该查询需要在SELECT
中的条件语句表达“如果A
页面中的TA
列具有值x
,则R1
,否则R2
”,R1
和R2
是相同类型的值(0
和1
或'ABC'
和'DEF'
) 。
通过CASE
它通常会给
SELECT CASE A WHEN x THEN R1 ELSE R2 END AS RA FROM TA;
要么
SELECT CASE WHEN A = x THEN R1 ELSE R2 END AS RA FROM TA;
这会产生一个错误,表示缺少运算符。
环顾四周我已经读过Access(因为没有人对Excel有关)没有CASE
声明。
我接着尝试了IIF
声明,
SELECT IIF (A = x, R1, R2) AS RA FROM TA;
哪个不起作用,错误告诉故事有关丢失的操作符或缺少ODBC字段取决于我如何表达条件(我使用香草CRecordset
对象,它在Open
调用失败,我不做DoFieldExchange
无处) ,
然后我尝试了SWITCH
声明
SELECT SWITCH (A = x, R1, true, R2) AS RA FROM TA;
哪个也失败了(“太少的争论.1预期。”),然后我尝试了CHOOSE
声明
SELECT CHOOSE (1*(A = x), R1, R2) AS RA FROM TA;
令人惊讶的是,它不起作用,结果相同。
我也用RA = ...
而不是... AS RA
尝试了所有这些查询,但无济于事。
如何通过ODBC在针对Excel文件的SQL查询中正确表达条件?
编辑:我知道假设无知是那里的常态,所以让我明白,[A]
是TA
中的一列,R1
和R2
只是表达了所需的值,在我的情况下,这些是字面值(分别是72
和70
)。我的查询也要大得多,从joins
请求wheres
和order by
的多个列,我所有的查询都运行良好,直到现在,我用CRecordset
来简单的GetFieldValue
对象。任何查询我都添加了条件语句以开始失败。我已经广泛调试了我的工作,并且我已经知道了查询格式正确(没有丢失的括号等)。我也没有实际知识这些陈述不受支持;我的语法更正可行。
我不能简单地让TA.A
处理它在代码中的值,我不能使用API或不同的驱动程序来访问数据。
Edit2:@Perfect:
CDatabase *here_db = new CDatabase () ;
here_db->OpenEx ("Driver={Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)};DBQ=C:\\ExcelFile.xls") ;
CRecordset *here_rs = new CRecordset (here_db) ;
here_rs->Open (CRecordset::snapshot, "SELECT COUNT(*) FROM [TableA$]", CRecordset::readOnly) ;
//This works, btw.
int rowCount ;
CDBVariant v ;
here_rs->GetFieldValue ((short) 0, v, SQL_C_SLONG) ;
rowCount = v.m_lVal ;
here_rs->Close () ;
here_rs->Open (CRecordset::snapshot, CString (
"SELECT"
" CASE A"
" WHEN 'test' THEN 72"
" ELSE 70"
" END AS RA"
" FROM [TableA$]"
""), CRecordset::readOnly) ;
short i ;
int colCount ;
colCount = here_rs->GetODBCFieldCount () ;
CString h ("") ;
while (!here_rs->IsEOF ())
{
for (i = 0; i < c; i++)
{
here_rs->GetFieldValue (i, h) ;
}
here_rs->MoveNext () ;
}
here_rs->Close () ;
delete here_rs ;
here_db->Close () ;
delete here_db ;
return TRUE ;
Edit3:这是CPP / Cli。
Jet和Ace数据提供程序使用OLEDB对象,我不知道您可以将它们与CDatabase / CRecordset一起使用。
我在周末结束后回到了这里,重建了我的查询,检查了所有表名,文件路径,列名等,尝试了IFF,并且它有效。使用Microsoft Excel驱动程序和所有。我假设我在某个地方犯了语法错误,但我不能为我的生活弄清楚它是什么。无论如何这里是结束工作的查询:
if (!here_rs->Open (CRecordset::snapshot,
"SELECT"
" `A`,"
" IIF(`A` = x, 72, 70) AS RA"
" FROM `TableA$`"
"", CRecordset::readOnly))
{
__debugbreak () ;
}
由于Parfait的答案是正确的,我会将其标记为正确。我仍然会欢迎解释发生了什么,如果有人的话。
在Windows环境中查询Excel工作簿将涉及JET / ACE SQL引擎(Windows .dll文件),这与MS Access中使用的引擎完全相同。由于这个SQL方言不支持ANSI的CASE
语句,最好的等价物是IIF
function。从你的陈述:
[A]是TA中的一列,R1和R2只表示所需的值
然后,如果使用字母数字,你的IIF
表达式必须将测试和所需的值视为带引号的文字。否则引擎会假定它们是表中的字段。请注意:您可以使用IIF
中的实际列。另外,使用表别名进行TA指定。
SELECT IIF(TA.A = 'test', 'R1', 'R2') AS RA
FROM [TableA$] AS TA
对于尝试代码中使用的数字值,请不要引用它们。在两个表达式中,您隐式分配数据类型(分别为字符串和整数),同时明确地将值分配给新计算列RA:
SELECT IIF(TA.A = 'test', 72, 70) AS RA
FROM [TableA$] AS TA