对于查询中的每个分区,做一个案例 select
For each partition in query, do a case select
来自 CTE 的以下查询结果:
+---------+----------+----------+----------+---------------------+
| STORE | DATE | TIME | RESPONSE | ROW_NUMBER_BY_STORE |
+---------+----------+----------+----------+---------------------+
| Store 1 | 11/15/19 | 15:37:40 | 1 | 1 |
+---------+----------+----------+----------+---------------------+
| Store 1 | 11/15/19 | 15:37:40 | 1 | 2 |
+---------+----------+----------+----------+---------------------+
| Store 1 | 11/15/19 | 16:55:12 | 2 | 3 |
+---------+----------+----------+----------+---------------------+
| Store 1 | 11/15/19 | 16:55:12 | 2 | 4 |
+---------+----------+----------+----------+---------------------+
我一直在尝试找出是否有任何方法可以在我的单个商店的查询结果中显示:
- 如果商店存在响应 1 和 2,我只想在结果中显示响应 1
- 如果商店仅存在响应 1,则不显示任何内容。
- 如果商店仅存在响应 2,则显示响应 2。
当然,我的 table 上有大量商店,我知道这可以通过 case 语句实现,但此查询中的 table 最初并未分区,并且我尝试添加一个 row_number() 函数并按 "store" 列进行分区,并将我的查询包装在 CTE 中以便能够查询行号函数,但似乎我只是不带着它去任何地方。所以我想知道是否有任何其他方法可以 运行 在每个行组上进行这样的查询。
编辑:
这是我的 CTE 的简化版本。不发布原件,因为它是一个包含大量连接的大型查询:
WITH CTE AS
(
SELECT
STORE_ID,
STORE,
CONVERT (varchar, INPUT_DATE, 103) AS DATE,
TIME,
RESPONSE,
ROW_NUMBER() OVER (PARTITION BY STORE ORDER BY STORE) AS STORE
FROM TABLE_1
WHERE INPUT_DATE BETWEEN 2019-11-15 AND 2019-11-15
)
SELECT *
FROM CTE
下面使用OUTER APPLY()
怎么样
DECLARE @Tab TABLE (STORE INT,DT DATE, TIME time(3), RESPONSE INT, ROW_NUMBER_BY_STORE INT)
INSERT INTO @Tab
VALUES
(1,'11/15/19','15:37:40',1,1),
(1,'11/15/19','15:37:40',1,2),
(1,'11/15/19','16:55:12',2,3),
(1,'11/15/19','16:55:12',2,4),
(2,'11/15/19','16:55:12',2,1),
(2,'11/15/19','16:55:12',2,2),
(3,'11/15/19','16:55:12',1,1),
(3,'11/15/19','16:55:12',1,2)
SELECT t.Store
, t.Dt
, t.Time
, CASE WHEN tt.DistinctResponse = 3 THEN 1
WHEN tt.DistinctResponse = 2 THEN 2
ELSE NULL END AS Response
, t.Row_Number_By_Store
FROM @Tab t
OUTER APPLY(
SELECT t2.Store, SUM(DISTINCT t2.Response) AS DistinctResponse
FROM @Tab t2
WHERE t2.Store = t.Store
GROUP BY t2.Store
) tt
这是一个同样从 CTE 开始的方法。
它使用 window 版本的 MIN 和 MAX。
还有一个用模数计算标志的技巧。
WITH CTE_DATA AS
(
SELECT
STORE
, CAST(dt AS DATE) AS [DATE]
, CAST(dt AS TIME) AS [TIME]
, RESPONSE
, ROW_NUMBER_BY_STORE
FROM (VALUES
('Store1','2019-11-15 15:37:40',1,1),
('Store1','2019-11-15 15:37:40',1,2),
('Store1','2019-11-15 16:55:12',2,3),
('Store1','2019-11-15 15:37:12',2,4),
('Store2','2019-11-16 15:37:40',1,1),
('Store2','2019-11-16 15:37:40',1,2),
('Store3','2019-11-17 16:55:12',2,3),
('Store3','2019-11-17 15:37:12',2,4)
) v(STORE, dt, RESPONSE, ROW_NUMBER_BY_STORE)
)
, CTE_DATA2 AS
(
SELECT *
, CAST(IIF((
RESPONSE
+ MIN(RESPONSE)
OVER (PARTITION BY STORE, [DATE])
+ MAX(RESPONSE)
OVER (PARTITION BY STORE, [DATE]))%2 = 1, 0, 1
) AS BIT) AS Flag
FROM CTE_DATA
)
SELECT STORE, [DATE], [TIME], RESPONSE, ROW_NUMBER_BY_STORE
FROM CTE_DATA2
WHERE Flag = 1
ORDER BY STORE, [DATE], ROW_NUMBER_BY_STORE;
GO
STORE | DATE | TIME | RESPONSE | ROW_NUMBER_BY_STORE
:----- | :------------------ | :------- | -------: | ------------------:
Store1 | 15/11/2019 00:00:00 | 15:37:40 | 1 | 1
Store1 | 15/11/2019 00:00:00 | 15:37:40 | 1 | 2
Store3 | 17/11/2019 00:00:00 | 16:55:12 | 2 | 3
Store3 | 17/11/2019 00:00:00 | 15:37:12 | 2 | 4
db<>fiddle here
我建议使用 window 函数,但像这样:
select cte.*
from (select cte.*,
sum(case when response = 1 then 1 else 0 end) over (partition by store) as response_1,
sum(case when response = 2 then 1 else 0 end) over (partition by store) as response_2
from cte
where response in (1, 2)
) cte
where response_2 > 0 and
(response_1 > 0 and response = 1 or
response_1 = 0 and response = 2
);
来自 CTE 的以下查询结果:
+---------+----------+----------+----------+---------------------+
| STORE | DATE | TIME | RESPONSE | ROW_NUMBER_BY_STORE |
+---------+----------+----------+----------+---------------------+
| Store 1 | 11/15/19 | 15:37:40 | 1 | 1 |
+---------+----------+----------+----------+---------------------+
| Store 1 | 11/15/19 | 15:37:40 | 1 | 2 |
+---------+----------+----------+----------+---------------------+
| Store 1 | 11/15/19 | 16:55:12 | 2 | 3 |
+---------+----------+----------+----------+---------------------+
| Store 1 | 11/15/19 | 16:55:12 | 2 | 4 |
+---------+----------+----------+----------+---------------------+
我一直在尝试找出是否有任何方法可以在我的单个商店的查询结果中显示:
- 如果商店存在响应 1 和 2,我只想在结果中显示响应 1
- 如果商店仅存在响应 1,则不显示任何内容。
- 如果商店仅存在响应 2,则显示响应 2。
当然,我的 table 上有大量商店,我知道这可以通过 case 语句实现,但此查询中的 table 最初并未分区,并且我尝试添加一个 row_number() 函数并按 "store" 列进行分区,并将我的查询包装在 CTE 中以便能够查询行号函数,但似乎我只是不带着它去任何地方。所以我想知道是否有任何其他方法可以 运行 在每个行组上进行这样的查询。
编辑:
这是我的 CTE 的简化版本。不发布原件,因为它是一个包含大量连接的大型查询:
WITH CTE AS
(
SELECT
STORE_ID,
STORE,
CONVERT (varchar, INPUT_DATE, 103) AS DATE,
TIME,
RESPONSE,
ROW_NUMBER() OVER (PARTITION BY STORE ORDER BY STORE) AS STORE
FROM TABLE_1
WHERE INPUT_DATE BETWEEN 2019-11-15 AND 2019-11-15
)
SELECT *
FROM CTE
下面使用OUTER APPLY()
DECLARE @Tab TABLE (STORE INT,DT DATE, TIME time(3), RESPONSE INT, ROW_NUMBER_BY_STORE INT)
INSERT INTO @Tab
VALUES
(1,'11/15/19','15:37:40',1,1),
(1,'11/15/19','15:37:40',1,2),
(1,'11/15/19','16:55:12',2,3),
(1,'11/15/19','16:55:12',2,4),
(2,'11/15/19','16:55:12',2,1),
(2,'11/15/19','16:55:12',2,2),
(3,'11/15/19','16:55:12',1,1),
(3,'11/15/19','16:55:12',1,2)
SELECT t.Store
, t.Dt
, t.Time
, CASE WHEN tt.DistinctResponse = 3 THEN 1
WHEN tt.DistinctResponse = 2 THEN 2
ELSE NULL END AS Response
, t.Row_Number_By_Store
FROM @Tab t
OUTER APPLY(
SELECT t2.Store, SUM(DISTINCT t2.Response) AS DistinctResponse
FROM @Tab t2
WHERE t2.Store = t.Store
GROUP BY t2.Store
) tt
这是一个同样从 CTE 开始的方法。
它使用 window 版本的 MIN 和 MAX。
还有一个用模数计算标志的技巧。
WITH CTE_DATA AS ( SELECT STORE , CAST(dt AS DATE) AS [DATE] , CAST(dt AS TIME) AS [TIME] , RESPONSE , ROW_NUMBER_BY_STORE FROM (VALUES ('Store1','2019-11-15 15:37:40',1,1), ('Store1','2019-11-15 15:37:40',1,2), ('Store1','2019-11-15 16:55:12',2,3), ('Store1','2019-11-15 15:37:12',2,4), ('Store2','2019-11-16 15:37:40',1,1), ('Store2','2019-11-16 15:37:40',1,2), ('Store3','2019-11-17 16:55:12',2,3), ('Store3','2019-11-17 15:37:12',2,4) ) v(STORE, dt, RESPONSE, ROW_NUMBER_BY_STORE) ) , CTE_DATA2 AS ( SELECT * , CAST(IIF(( RESPONSE + MIN(RESPONSE) OVER (PARTITION BY STORE, [DATE]) + MAX(RESPONSE) OVER (PARTITION BY STORE, [DATE]))%2 = 1, 0, 1 ) AS BIT) AS Flag FROM CTE_DATA ) SELECT STORE, [DATE], [TIME], RESPONSE, ROW_NUMBER_BY_STORE FROM CTE_DATA2 WHERE Flag = 1 ORDER BY STORE, [DATE], ROW_NUMBER_BY_STORE; GO
STORE | DATE | TIME | RESPONSE | ROW_NUMBER_BY_STORE :----- | :------------------ | :------- | -------: | ------------------: Store1 | 15/11/2019 00:00:00 | 15:37:40 | 1 | 1 Store1 | 15/11/2019 00:00:00 | 15:37:40 | 1 | 2 Store3 | 17/11/2019 00:00:00 | 16:55:12 | 2 | 3 Store3 | 17/11/2019 00:00:00 | 15:37:12 | 2 | 4
db<>fiddle here
我建议使用 window 函数,但像这样:
select cte.*
from (select cte.*,
sum(case when response = 1 then 1 else 0 end) over (partition by store) as response_1,
sum(case when response = 2 then 1 else 0 end) over (partition by store) as response_2
from cte
where response in (1, 2)
) cte
where response_2 > 0 and
(response_1 > 0 and response = 1 or
response_1 = 0 and response = 2
);