我需要通过ODBC和Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)
.构建SQL查询来读取Excel文件。
该查询需要SELECT
中的一个条件语句,该语句表示“如果来自页面TA
的列A
的值为x
,则为R1
,否则为R2
",R1
和R2
为相同类型的值(0
和1
或'ABC'
和d14)。
对于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 )。我的查询也要大得多,使用wheres和order by从wheres请求多个列,到目前为止,我的所有查询都运行良好,使用了简单的CRecordset对象,我可以从这些对象中调用GetFieldValue。任何我添加了条件语句的查询都开始失败。我已经广泛地调试了我的工作,就我所知,查询的格式是正确的(没有遗漏括号之类的)。我也不知道这些声明是不受支持的;对我的语法进行更正是值得欢迎的。
我不能简单地获得TA.A,然后在代码中处理它的值,也不能使用API或其他驱动程序来访问数据。
Edit2:@Parfait:
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。
CDatabase数据提供者使用OLEDB对象,我不知道您是否可以将它们与CDatabase/CRecordset一起使用。
在周末之后,我又回到了这个问题,重新构建了我的查询,检查了所有的表名、文件路径、列名等等,尝试了IFF,它成功了。使用Microsoft驱动程序等等。我假设我在某个地方犯了语法错误,但我无法理解它是什么。无论如何,这里是结束工作的查询:
if (!here_rs->Open (CRecordset::snapshot,
"SELECT"
" `A`,"
" IIF(`A` = x, 72, 70) AS RA"
" FROM `TableA$`"
"", CRecordset::readOnly))
{
__debugbreak () ;
}
既然Parfait的答案是正确的,我就把它标记成这样。如果有人知道的话,我还是欢迎你解释一下发生了什么。
发布于 2019-03-08 17:22:23
在Windows环境中查询Excel工作簿将涉及JET/ Access引擎(Windows .dll文件),这是MS Access中使用的完全相同的引擎。因为这个SQL方言不支持ANSI的CASE
语句,所以最好的等效语言是 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
https://stackoverflow.com/questions/55065382
复制相似问题