如果与内部查询一起使用,SQL server pivot count函数将无法正常工作
我认为我的SQL server pivot函数中有一个bug,因为我找不到任何其他解释 我正在运行一个简单的pivot,并使用MSDN中显示的确切语法。 但是pivot答案显示了所有列的完全相同的数字,其值等于所有周的计数!!! (左边是查询结果,右边是我想要的) 我的问题是:如果与内部查询一起使用,SQL server pivot count函数将无法正常工作,sql,sql-server,pivot,pivot-table,Sql,Sql Server,Pivot,Pivot Table,我认为我的SQL server pivot函数中有一个bug,因为我找不到任何其他解释 我正在运行一个简单的pivot,并使用MSDN中显示的确切语法。 但是pivot答案显示了所有列的完全相同的数字,其值等于所有周的计数!!! (左边是查询结果,右边是我想要的) 我的问题是: SELECT * FROM (SELECT r.cutomer_id ,c.[Week] ,r.id FROM r JOIN c ON r.Create_date = c.Dat
SELECT
*
FROM (SELECT
r.cutomer_id
,c.[Week]
,r.id
FROM r
JOIN c
ON r.Create_date = c.Date
WHERE Is_ride = 1
AND ((Create_date_int BETWEEN 20190302 AND 20190319)
OR (Create_date_int BETWEEN 20190406 AND 20190426))) p
PIVOT
(
COUNT(id)
FOR [Week] IN
([9], [10], [11], [12], [14], [15], [16], [17])
) AS pvt
下面是一些表示“p”输出的测试数据(我刚刚更改了id号,周数与您从查询中得到的相同)
因此,我认为我的查询有问题,但后来我将查询更改为:
SELECT
r.cutomer_id
,c.[Week]
,r.id INTO #t
FROM r
JOIN c
ON r.Create_date = c.Date
WHERE Is_ride = 1
AND ((Create_date_int BETWEEN 20190302 AND 20190319)
OR (Create_date_int BETWEEN 20190406 AND 20190426))
SELECT
*
FROM #t
PIVOT
(
COUNT(id)
FOR [Week] IN
([9], [10], [11], [12], [14], [15], [16], [17])
) AS pvt
而且效果很好!
另外,如果我从select中删除r.id列,并将其更改为count(week)
它工作正常
如果我只将我的where
更改为
WHERE Is_ride = 1
AND ((Create_date_int BETWEEN 20190302 AND 20190319)
OR (Create_date_int BETWEEN 20190406 AND 20190426))
and passenger_id in (43551,12032,136019)
) p
它很好用
有人能给我一个解释吗?我不知道你为什么会在图像上看到结果。可能丢失了一些信息。 下面是一个MVCE,其中的代码被注释以创建更大的测试数据集
CREATE TABLE r(
id int identity,
customer_id int,
create_date date,
Create_date_int AS CONVERT( int, CONVERT( char(8), create_date, 112)),
is_ride bit)
INSERT INTO r(customer_id, create_date, is_ride)
SELECT customer_id, '20190307', 1
FROM (VALUES(1),(2),(3),(4),(5),(6),(7),(8),(9),(10))x(customer_id)
--SELECT TOP 100000
-- ABS(CHECKSUM(NEWID())) % 10,
-- DATEADD( dd, ABS(CHECKSUM(NEWID())) % 120, '2019'),
-- 1
--FROM sys.all_columns a, sys.all_columns b;
CREATE TABLE c(
[Date] date,
[Week] AS DATEPART( wk, [Date])
)
INSERT INTO c([Date])
SELECT DATEADD( dd, ROW_NUMBER() OVER( ORDER BY (SELECT NULL))-1, '2019')
FROM sys.all_columns;
从这里,我可以运行您最初的查询,得到预期的结果,在第10周只需1个
我还可以使用交叉表运行替代查询,这是我首选的数据透视方法
SELECT
r.customer_id
,COUNT( CASE WHEN c.[Week] = 9 THEN r.id END) AS wk9
,COUNT( CASE WHEN c.[Week] = 10 THEN r.id END) AS wk10
,COUNT( CASE WHEN c.[Week] = 11 THEN r.id END) AS wk11
,COUNT( CASE WHEN c.[Week] = 12 THEN r.id END) AS wk12
,COUNT( CASE WHEN c.[Week] = 14 THEN r.id END) AS wk14
,COUNT( CASE WHEN c.[Week] = 15 THEN r.id END) AS wk15
,COUNT( CASE WHEN c.[Week] = 16 THEN r.id END) AS wk16
,COUNT( CASE WHEN c.[Week] = 17 THEN r.id END) AS wk17
FROM r
JOIN c ON r.Create_date = c.Date
WHERE Is_ride = 1
AND (Create_date_int BETWEEN 20190302 AND 20190319
OR Create_date_int BETWEEN 20190406 AND 20190426)
GROUP BY r.customer_id
ORDER BY r.customer_id;
这也提供了正确的信息
这两种方法都可以通过预聚集来提高性能
WITH ctePreAggregate AS(
SELECT
r.customer_id
,c.[Week]
,COUNT(*) AS weeklycount
FROM r
JOIN c
ON r.Create_date = c.Date
WHERE Is_ride = 1
AND (Create_date_int BETWEEN 20190302 AND 20190319
OR Create_date_int BETWEEN 20190406 AND 20190426)
GROUP BY r.customer_id
,c.[Week]
)
SELECT
*
FROM ctePreAggregate
PIVOT
(
SUM(weeklycount)
FOR [Week] IN
([9], [10], [11], [12], [14], [15], [16], [17])
) AS pvt
ORDER BY customer_id;
WITH ctePreAggregate AS(
SELECT
r.customer_id
,c.[Week]
,COUNT(*) AS weeklycount
FROM r
JOIN c
ON r.Create_date = c.Date
WHERE Is_ride = 1
AND (Create_date_int BETWEEN 20190302 AND 20190319
OR Create_date_int BETWEEN 20190406 AND 20190426)
GROUP BY r.customer_id
,c.[Week]
)
SELECT
customer_id
,SUM( CASE WHEN [Week] = 9 THEN weeklycount ELSE 0 END) AS wk9
,SUM( CASE WHEN [Week] = 10 THEN weeklycount ELSE 0 END) AS wk10
,SUM( CASE WHEN [Week] = 11 THEN weeklycount ELSE 0 END) AS wk11
,SUM( CASE WHEN [Week] = 12 THEN weeklycount ELSE 0 END) AS wk12
,SUM( CASE WHEN [Week] = 14 THEN weeklycount ELSE 0 END) AS wk14
,SUM( CASE WHEN [Week] = 15 THEN weeklycount ELSE 0 END) AS wk15
,SUM( CASE WHEN [Week] = 16 THEN weeklycount ELSE 0 END) AS wk16
,SUM( CASE WHEN [Week] = 17 THEN weeklycount ELSE 0 END) AS wk17
FROM ctePreAggregate
GROUP BY customer_id
ORDER BY customer_id;
唯一的问题是,您需要在列列表中添加一系列ISNULL(),以便为PIVOT查询显示null而不是零。“它工作正常!!!”我非常怀疑它工作正常,因为SQL表/结果集按SQL定义是无序的,所以使用
TOP
和ORDER by
是毫无意义的。。事实上,它可能导致返回非确定性(随机)结果。。要始终获得确定性(固定)结果,您应该至少包含一个列,该列具有主键、唯一键,或者您知道该列具有(几乎)唯一的值,如datetime,按顺序为7分秒,假设当您开始大量删除或更新内容,并且表/索引碎片化成为一件事情时,它将不再正常工作。。我警告过你,如果你想继续用你的查询结果玩俄罗斯轮盘赌,那么这是你的选择。对于任何在这里帮助你的人,你需要提供一个再现问题或实际执行计划(XML)的MVCE。当然,如果将完全相同的行插入临时表而不是派生表,PIVOT不应返回不同的结果。可能是数据库中的某种损坏,一个bug,或者你的描述库中缺少什么,Martin。我们有非常敏感的数据和安全的服务器,很难创建MVCE。这些是我使用的完全相同的查询,我得到了完全不同的结果!如果没有任何解释,我想我的数据库可能有问题!我会检查/重建索引,或者尝试使用查询来缩小问题范围。
WITH ctePreAggregate AS(
SELECT
r.customer_id
,c.[Week]
,COUNT(*) AS weeklycount
FROM r
JOIN c
ON r.Create_date = c.Date
WHERE Is_ride = 1
AND (Create_date_int BETWEEN 20190302 AND 20190319
OR Create_date_int BETWEEN 20190406 AND 20190426)
GROUP BY r.customer_id
,c.[Week]
)
SELECT
*
FROM ctePreAggregate
PIVOT
(
SUM(weeklycount)
FOR [Week] IN
([9], [10], [11], [12], [14], [15], [16], [17])
) AS pvt
ORDER BY customer_id;
WITH ctePreAggregate AS(
SELECT
r.customer_id
,c.[Week]
,COUNT(*) AS weeklycount
FROM r
JOIN c
ON r.Create_date = c.Date
WHERE Is_ride = 1
AND (Create_date_int BETWEEN 20190302 AND 20190319
OR Create_date_int BETWEEN 20190406 AND 20190426)
GROUP BY r.customer_id
,c.[Week]
)
SELECT
customer_id
,SUM( CASE WHEN [Week] = 9 THEN weeklycount ELSE 0 END) AS wk9
,SUM( CASE WHEN [Week] = 10 THEN weeklycount ELSE 0 END) AS wk10
,SUM( CASE WHEN [Week] = 11 THEN weeklycount ELSE 0 END) AS wk11
,SUM( CASE WHEN [Week] = 12 THEN weeklycount ELSE 0 END) AS wk12
,SUM( CASE WHEN [Week] = 14 THEN weeklycount ELSE 0 END) AS wk14
,SUM( CASE WHEN [Week] = 15 THEN weeklycount ELSE 0 END) AS wk15
,SUM( CASE WHEN [Week] = 16 THEN weeklycount ELSE 0 END) AS wk16
,SUM( CASE WHEN [Week] = 17 THEN weeklycount ELSE 0 END) AS wk17
FROM ctePreAggregate
GROUP BY customer_id
ORDER BY customer_id;