【问题标题】:Query returning different number of rows, results in crosstab error查询返回不同的行数,导致交叉表错误
【发布时间】:2018-04-07 02:39:35
【问题描述】:

我的查询出现此错误,但我无法弄清楚它有什么问题:

查询指定的返回元组有 135 列,但交叉表返回 295。

这是我的查询:(以粗体突出显示的部分在 pgAdmin 中单独运行时返回相同数量的行。)

SELECT X.*, pi.productcode, pi.productitemdesc, pi.retailsalesprice, cat.productcategorydesc FROM ( 
SELECT * FROM crosstab ( 
'SELECT a.productitem AS productitemid, l.locationcode, (CASE WHEN SUM(a.netamount) IS NOT NULL THEN SUM(a.netamount) ELSE 0 END) || ''#'' || (CASE WHEN SUM(a.quantity) IS NOT NULL THEN SUM(a.quantity) ELSE 0 END) AS sales_qty FROM invoiceitem a INNER JOIN invoiceinfo b ON a.invoice = b.invoiceid INNER JOIN locationinfo l ON b.location = l.locationid WHERE b.status !=2 AND l.locationtype = 1 AND l.status = 1 AND TO_CHAR (b.invoicedate, ''YYYY-MM-DD'')>=''2018-03-01'' AND TO_CHAR (b.invoicedate, ''YYYY-MM-DD'')<=''2018-03-03'' GROUP BY a.productitem, l.locationcode ORDER BY a.productitem', 
'SELECT l.locationcode FROM locationinfo l INNER JOIN invoiceinfo b ON b.location = l.locationid
 WHERE b.status !=2 AND l.locationtype = 1 AND l.status = 1 AND TO_CHAR (b.invoicedate, ''YYYY-MM-DD'')>=''2018-03-01'' AND TO_CHAR (b.invoicedate, ''YYYY-MM-DD'')<=''2018-03-03'' GROUP BY l.locationcode order by l.locationcode') 
 AS (productitemid int, "0007" text,"BE101" text,"BE1013" text,"BE1014" text,"BE102" text,"BE103" text,"BE1034" text,"BE104" text,"BE1040" text,"BE1043" text,"BE1044" text,"BE1045" text,"BE1046" text,"BE105" text,"BE106" text,"BE107" text,"BE108" text,"BE109" text,"BE110" text,"BE111" text,"BE112" text,"BE123" text,"BE1265" text,"BE1266" text,"BE1271" text,"BE1272" text,"BE1273" text,"BE1274" text,"BE1279" text,"BE1280" text,"BE1281" text,"BE1282" text,"BE1351" text,"BE1400" text,"BE1401" text,"BE1404" text,"BE141" text,"BE142" text,"BE193" text,"BE194" text,"BE2125" text,"BE2126" text,"BE2127" text,"BE2128" text,"BE3001" text,"BE3002" text,"BE3005" text,"BE3006" text,"BE3009" text,"BE3010" text,"BE3031" text,"BE3032" text,"BE3121" text,"BE3122" text,"BE3123" text,"BE3124" text,"BE3127" text,"BE3128" text,"BE3131" text,"BE3132" text,"BE3203" text,"BE3204" text,"BE325" text,"BE3253" text,"BE3254" text,"BE326" text,"BE332" text,"BE3503" text,"BE3504" text,"BE355" text,"BE356" text,"BE365" text,"BE366" text,"BE381" text,"BE382" text,"BE383" text,"BE384" text,"BE400" text,"BE401" text,"BE402" text,"BE403" text,"BE405" text,"BE406" text,"BE408" text,"BE409" text,"BE411" text,"BE412" text,"BE4311" text,"BE4316" text,"BE4401" text,"BE4402" text,"BE4521" text,"BE4522" text,"BE4551" text,"BE4552" text,"BE470" text,"BE473" text,"BE475" text,"BE481" text,"BE482" text,"BE601" text,"BE604" text,"BE609" text,"BE610" text,"BE7040" text,"BE7043" text,"BE7045" text,"BE7046" text,"BE7048" text,"BE7049" text,"BE708" text,"BE7111" text,"BE7112" text,"BE7127" text,"BE7128" text,"BE7217" text,"BE7218" text,"BE7307" text,"BE7308" text,"BE7351" text,"BE7352" text,"BE801" text,"BE802" text,"BE803" text,"BE804" text,"BE831" text,"BE832" text,"BE860" text,"BE861" text,"BE862" text,"BE863" text,"BE865" text,"BE981" text,"BE982" text 
 )) X
 LEFT JOIN productitem pi ON X.productitemid = pi.productitemid
 LEFT JOIN productcategory cat ON pi.productcategory = cat.productcategoryid

的粗体部分
productitemid int, "0007" text,"BE101" text,"BE1013" text,"BE1014" text,"BE102" text,"BE103" text,"BE1034" text,"BE104" text,"BE1040" text,"BE1043" text,"BE1044" text,"BE1045" text,"BE1046" text,"BE105" text,"BE106" text,"BE107" text,"BE108" text,"BE109" text,"BE110" text,"BE111" text,"BE112" text,"BE123" text,"BE1265" text,"BE1266" text,"BE1271" text,"BE1272" text,"BE1273" text,"BE1274" text,"BE1279" text,"BE1280" text,"BE1281" text,"BE1282" text,"BE1351" text,"BE1400" text,"BE1401" text,"BE1404" text,"BE141" text,"BE142" text,"BE193" text,"BE194" text,"BE2125" text,"BE2126" text,"BE2127" text,"BE2128" text,"BE3001" text,"BE3002" text,"BE3005" text,"BE3006" text,"BE3009" text,"BE3010" text,"BE3031" text,"BE3032" text,"BE3121" text,"BE3122" text,"BE3123" text,"BE3124" text,"BE3127" text,"BE3128" text,"BE3131" text,"BE3132" text,"BE3203" text,"BE3204" text,"BE325" text,"BE3253" text,"BE3254" text,"BE326" text,"BE332" text,"BE3503" text,"BE3504" text,"BE355" text,"BE356" text,"BE365" text,"BE366" text,"BE381" text,"BE382" text,"BE383" text,"BE384" text,"BE400" text,"BE401" text,"BE402" text,"BE403" text,"BE405" text,"BE406" text,"BE408" text,"BE409" text,"BE411" text,"BE412" text,"BE4311" text,"BE4316" text,"BE4401" text,"BE4402" text,"BE4521" text,"BE4522" text,"BE4551" text,"BE4552" text,"BE470" text,"BE473" text,"BE475" text,"BE481" text,"BE482" text,"BE601" text,"BE604" text,"BE609" text,"BE610" text,"BE7040" text,"BE7043" text,"BE7045" text,"BE7046" text,"BE7048" text,"BE7049" text,"BE708" text,"BE7111" text,"BE7112" text,"BE7127" text,"BE7128" text,"BE7217" text,"BE7218" text,"BE7307" text,"BE7308" text,"BE7351" text,"BE7352" text,"BE801" text,"BE802" text,"BE803" text,"BE804" text,"BE831" text,"BE832" text,"BE860" text,"BE861" text,"BE862" text,"BE863" text,"BE865" text,"BE981" text,"BE982" text

SELECT l.locationcode FROM locationinfo l INNER JOIN invoiceinfo b ON b.location = l.locationid
 WHERE b.status !=2 AND l.locationtype = 1 AND l.status = 1 AND TO_CHAR (b.invoicedate, ''YYYY-MM-DD'')>=''2018-03-01'' AND TO_CHAR (b.invoicedate, ''YYYY-MM-DD'')&lt;=''2018-03-03'' GROUP BY l.locationcode order by l.locationcode

单独运行时,我得到 295 个结果,这是正确的。但是,将它放在整个查询中会出现错误。

【问题讨论】:

  • 如果交叉表返回 295 列,如果你全部返回,那么列数应该是 295 作为回报。如果你只需要 135 列交叉表应该只返回 135
  • "相同的行数" ...与哪个数字相同?我是否正确假设您的专栏 invoiceinfo.invoicedate 是类型 timestamptz
  • @ErwinBrandstetter 感谢您的评论,我已在更新的问题中提供了详细信息。太棒了!
  • @parladneupane 感谢您的评论。如果我将两个查询分开,我得到相同的数字,即 295,但是当我输入整个查询时,我得到了错误。我已经更新了我的问题。希望能解释更多。非常感谢
  • @Sylph:数据类型呢?

标签: postgresql crosstab pgadmin


【解决方案1】:

The manual:

剩余的输出列必须具有 source_sql 查询结果的最后一列的类型,并且它们的数量必须与 @987654327 中的行数完全相同@ 查询结果。

crosstab(text, text) 使用动态 (!) SELECT 查询作为第二个参数很容易出错,因为输出列列表是静态的。您还应该动态生成输出列列表。示例:

除此之外,从同一查询返回的行数不同,很可能是由于两个不同会话中的 timezone 设置不同。

您的谓词中有表达式TO_CHAR(b.invoicedate, 'YYYY-MM-DD')。如果b.invoicedate键入timestamptz,则结果取决于timezone 设置。考虑:

SET timezone = '+10';
SELECT TO_CHAR(timestamptz '2018-04-07 23:30+0', 'YYYY-MM-DD');

to_char
----------
2018-04-08

SET timezone = '-10';
SELECT TO_CHAR(timestamptz '2018-04-07 23:30+0', 'YYYY-MM-DD');

to_char
----------
2018-04-07

解决方案

要消除对timezone 设置的依赖,请使用绝对值。

我建议将此作为第二个参数:

$$
SELECT l.locationcode
FROM   locationinfo l
JOIN   invoiceinfo  b ON b.location = l.locationid
WHERE  b.status <> 2 AND l.locationtype = 1 AND l.status = 1
AND    b.invoicedate >=  timestamptz '2018-03-01 Europe/Vienna'
AND    b.invoicedate <   timestamptz '2018-03-04 Europe/Vienna'
GROUP  BY 1
ORDER  BY 1
$$

将我的示例中的 Europe/Vienna 替换为定义日期的时区名称。
请注意 2018-03-04 以按照您的意图包含所有 2018-03-03。

【讨论】:

  • 非常感谢您的帮助。我刚刚检查了一下,发票数据类型是:没有时区的时间戳。如果是这种情况,您知道可能出了什么问题吗?我也尝试使用你的方法,但仍然有同样的错误。顺便说一句,非常感谢您在上面的帮助,每天都在学习新东西。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-10-27
  • 1970-01-01
  • 2012-01-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多