在SQL Server中进行分组,再按多个参数分组,然后按参数对结果进行联接

时间:2019-03-07 01:13:58

标签: sql-server

我无法拿出更好的头衔。

我有一个具有以下结构的表:

id | timestamp | barcode

我需要获取每天每种产品的数量,并通过一个查询进行轮换。

Productleft(barcode, 9)date应该来自timestampdatetime并且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在开始的那天显示出来,然后对它的项目计数进行计数,直到第二天结束为止。

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