我无法拿出更好的头衔。
我有一个具有以下结构的表:
id | timestamp | barcode
我需要获取每天每种产品的数量,并通过一个查询进行轮换。
Product
是left(barcode, 9)
,date
应该来自timestamp
,datetime
并且shift
也应该来自时间戳。移位如下:
Shift 1 : 06:00:00 to 14:29:59
Shift 2 : 14:30:00 to 22:59:59
Shift 3 : 23:00:00 to 05:59:59
所以我基本上需要这样的结果:
date | shift | item number | count
12.02.2019 | 1 | 827384950 | 32
到目前为止,我有这个:
select cast(timestamp as date) as date,
(case when convert(time, timestamp) >= '06:00:00' and
convert(time, timestamp) < '14:30:00'
then 1
when convert(time, timestamp) >= '14:30:00' and
convert(time, timestamp) < '23:00:00'
then 2
else 3
end) as shift,
left(barcode, 9) as item_number,
count(*)
from t
group by cast(timestamp as date),
(case when convert(time, timestamp) >= '06:00:00' and
convert(time, timestamp) < '14:30:00'
then 1
when convert(time, timestamp) >= '14:30:00' and
convert(time, timestamp) < '23:00:00'
then 2
else 3
end),
left(barcode, 9)
order by date, shift, item_number;
它可以完成工作,但是问题是这样的:
轮班3实际上是在两天内参加的,因为它是从一天的23:00到第二天的6。这段代码将班次3分为两部分-每天一次。
我需要对其进行分组,以便Shift 3在开始的那天显示出来,然后对它的项目计数进行计数,直到第二天结束为止。
答案 0 :(得分:3)
我喜欢将复杂的逻辑排除在GROUP BY
子句之外,这样,当其他人来阅读代码时,他们可以清楚地掌握分组的逻辑。相反,我将逻辑分离为CTE的SELECT
语句,并在简单易读的查询中使用结果列。
;WITH cte AS
(
SELECT id, LEFT(barcode, 9) item_number,
CONVERT(DATE, CASE WHEN CONVERT(TIME, timestamp) <'06:00:00' THEN DATEADD(DAY, -1, timestamp) ELSE timestamp END) AS date,
CASE WHEN CONVERT(TIME, timestamp) >= '06:00:00' AND
CONVERT(TIME, timestamp) < '14:30:00'
THEN 1
WHEN CONVERT(TIME, timestamp) >= '14:30:00' AND
CONVERT(TIME, timestamp) < '23:00:00'
THEN 2
ELSE 3
END AS shift
FROM Table t
)
SELECT date, shift, item_number, count(*) as count
FROM cte
GROUP BY date, shift, item_number
答案 1 :(得分:0)
请尝试以下操作:
SELECT CASE WHEN a.shift = 3 AND a.[time] < '06:00' THEN DATEADD(DAY,-1,a.[date]) ELSE a.[date] END AS [date]
,a.shift,a.item_number,COUNT(*)
FROM (
SELECT TRY_CONVERT(DATE,t.[timestamp]) AS [date]
,TRY_CONVERT(TIME,t.timestamp) AS [time]
,CASE
WHEN TRY_CONVERT(TIME,t.timestamp) >= '23:00' OR TRY_CONVERT(TIME,t.timestamp) < '06:00' THEN 3
WHEN TRY_CONVERT(TIME,t.timestamp) >= '14:30' THEN 2
ELSE 1
END AS [shift]
,LEFT(t.barcode,9) AS [item_number]
FROM [YourTableName] t
) a
GROUP BY CASE WHEN a.shift = 3 AND a.[time] < '06:00' THEN DATEADD(DAY,-1,a.[date]) ELSE a.[date] END
,a.shift,a.item_number
;
答案 2 :(得分:0)
如果您要测试一些样本数据,那就太好了!
从本质上讲,我将时间戳向后移6小时,以避免跨天第三班的混乱。它将完整的3班次拉到该班次开始的日期,而不会丢失1班次的日期(因为00:00算作该日期)。
SELECT TheDay = TRY_CONVERT(DATE, DATEADD(HOUR, -6, t.[timestamp])),
Shift = CASE
WHEN TRY_CONVERT(TIME, DATEADD(HOUR, -6, t.[timestamp])) < '08:30'
THEN 1
WHEN TRY_CONVERT(TIME, DATEADD(HOUR, -6, t.[timestamp])) < '17:00'
THEN 2
ELSE 3
END,
Product = LEFT(t.[barcode], 9),
ItemCount = COUNT(*)
FROM [TableName] t
GROUP BY TRY_CONVERT(DATE, DATEADD(HOUR, -6, t.[timestamp])),
CASE
WHEN TRY_CONVERT(TIME, DATEADD(HOUR, -6, t.[timestamp])) < '08:30'
THEN 1
WHEN TRY_CONVERT(TIME, DATEADD(HOUR, -6, t.[timestamp])) < '17:00'
THEN 2
ELSE 3
END,
LEFT(t.[barcode], 9)
@elizabk说得很对:
;WITH shiftedData (TheDay, Shift, Product) AS (
SELECT TheDay = TRY_CONVERT(DATE, DATEADD(HOUR, -6, t.[timestamp])),
Shift = CASE
WHEN TRY_CONVERT(TIME, DATEADD(HOUR, -6, t.[timestamp])) < '08:30'
THEN 1
WHEN TRY_CONVERT(TIME, DATEADD(HOUR, -6, t.[timestamp])) < '17:00'
THEN 2
ELSE 3
END,
Product = LEFT(t.[barcode], 9)
FROM [TableName] t
)
SELECT TheDay, Shift, Product, ProductCount = COUNT(*)
FROM shiftedData
GROUP BY TheDay, Shift, Product