如何做多个CTE的联合

时间:2016-06-27 13:26:07

标签: sql sql-server sql-server-2008

我有两个查询,如下所示

查询1

set @sql = cast(N'
;with cteSales as
(
  select
    datepart(weekday, s.enddate) as SalesWeekDay,
    datediff(hour, cast(s.enddate as date), s.enddate) DayTime,
    s.enddate SalesDate,
    CONVERT(DECIMAL(10,2),OrigionalSubTotal/100.0) as OrigionalSubTotal,
    o.ordertype ordertype
  from sale s,DinePointOrderType o
  where s.enddate >= @DateBegin and s.enddate < @DateEnd
 and o.ordertypeindex = s.ordertype
 and s.ordertype = 1
  and s.IsSuspend = 0  and s.IsTrainMode = 0
  and s.IsCancelled = 0 and s.wasrefunded=0
),
cteSalesPerWeekDays as
(
  select
    p.hrs,
    p.period,
    isnull(p.ordertype,''DINE IN'') ordertype,' as nvarchar(max)) + @col_per_day_list + N'
  from #Timing t
  cross join #WeekDays w
  left join cteSales s on datediff(hour, w.wd_date, s.SalesDate) = t.hrs
  pivot
  (
    Sum(s.OrigionalSubTotal)
    for w.wd_name in (' + @pivot_val_per_day_list + N')
  ) p
)

select
  r.hrs,
  r.period as [From-To],
  r.ordertype,' + @sum_cols_per_day_list + N'
from cteSalesPerWeekDays r
group by r.hrs, r.period,r.ordertype
order by r.hrs

'
exec sp_executesql @sql, N'@DateBegin datetime, @DateEnd datetime',
  @DateBegin = @DateBegin,
  @DateEnd = @TradeDateEnd

GO

查询2

set @sql = cast(N'
;with cteSales as
(
  select
    datepart(weekday, s.enddate) as SalesWeekDay,
    datediff(hour, cast(s.enddate as date), s.enddate) DayTime,
    s.enddate SalesDate,
    CONVERT(DECIMAL(10,2),OrigionalSubTotal/100.0) as OrigionalSubTotal,
    o.ordertype ordertype
  from sale s,DinePointOrderType o
  where s.enddate >= @DateBegin and s.enddate < @DateEnd
 and o.ordertypeindex = s.ordertype
 and s.ordertype = 2
  and s.IsSuspend = 0  and s.IsTrainMode = 0
  and s.IsCancelled = 0 and s.wasrefunded=0
),
cteSalesPerWeekDays as
(
  select
    p.hrs,
    p.period,
    isnull(p.ordertype,''TAKE OUT'') ordertype,' as nvarchar(max)) + @col_per_day_list + N'
  from #Timing t
  cross join #WeekDays w
  left join cteSales s on datediff(hour, w.wd_date, s.SalesDate) = t.hrs
  pivot
  (
    Sum(s.OrigionalSubTotal)
    for w.wd_name in (' + @pivot_val_per_day_list + N')
  ) p
)

select
  r.hrs,
  r.period as [From-To],
  r.ordertype,' + @sum_cols_per_day_list + N'
from cteSalesPerWeekDays r
group by r.hrs, r.period,r.ordertype
order by r.hrs

'


exec sp_executesql @sql, N'@DateBegin datetime, @DateEnd datetime',
  @DateBegin = @DateBegin,
  @DateEnd = @TradeDateEnd

是否可以将这两个查询联合起来?

2 个答案:

答案 0 :(得分:1)

您需要在此行上开始新的CAST:

  isnull(p.ordertype,''DINE IN'') ordertype,' as nvarchar(max)) + @col_per_day_list + N'

像这样:

  isnull(p.ordertype,''DINE IN'') ordertype,' as nvarchar(max)) + @col_per_day_list + CAST(N'

编辑,现在修复了该错误,你的UNION位置错误。

你不能UNION这两个CTE:

cteSalesPerWeekDays as
(...)
union
cteSales as
(...)

您只能在两个SELECT语句之间使用UNION。所以你可以制作你的CTE的Dine In和Take Out版本,然后在最终的选择中UNION它们:

SELECT ...
FROM cteSalesPerWeekDaysDINEIN
UNION 
SELECT ...
FROM cteSalesPerWeekDaysTAKEOUT

答案 1 :(得分:0)

这么多代码......只需使用PIVOT和动态SQL就可以完成。

创建表以测试输出:

CREATE TABLE #Ordertypes (
    ordertype_id int, 
    name nvarchar(10)
)

INSERT INTO #Ordertypes VALUES
(1, 'DINE IN'),
(2, 'TAKE OUT'),
(3, 'DELIVERY')


CREATE TABLE #Sale (
    StartDate datetime, 
    Amt money, 
    ordertype_id int
)

INSERT INTO #Sale VALUES
('2016-06-12 10:01:15.780', 10.00, 1),
('2016-06-12 10:15:57.360', 20.00, 1),
('2016-06-12 12:48:41.250', 50.00, 2),
('2016-06-13 12:04:45.090', 15.00, 3)

CREATE TABLE #time_intervals (
    tStart time,
    tEnd time
)

;WITH time_intervals AS (
SELECT  CAST('00:00:00' as time) as tStart,
        CAST('00:59:59' as time) as tEnd
UNION ALL
SELECT  DATEADD(hour,1,tStart),
        DATEADD(hour,1,tEnd)
FROM time_intervals
WHERE tEnd < CAST('23:59:59' as time)
)

INSERT INTO #time_intervals
SELECT *
FROM time_intervals

主要查询:

DECLARE @dateFrom date = '2016-06-12',
        @dateTo date = '2016-06-13'

DECLARE @sql nvarchar(max),
        @columns nvarchar(max),
        @cast_columns nvarchar(max)

SELECT @cast_columns= STUFF((
    SELECT DISTINCT ',ISNULL(' + QUOTENAME(CAST(StartDate as date)) +',0.00) as ' + QUOTENAME(CAST(StartDate as date))
    FROM #Sale
    WHERE CAST(StartDate as date) between @dateFrom and @dateTo
    FOR XML PATH('')),1,1,''),
    @columns = STUFF((
    SELECT DISTINCT ',' + QUOTENAME(CAST(StartDate as date))
    FROM #Sale
    WHERE CAST(StartDate as date) between @dateFrom and @dateTo
    FOR XML PATH('')),1,1,'')

SELECT @sql = '
SELECT  LEFT(tStart,5) + ''-'' + LEFT(DATEADD(second,1,tEnd),5) as Interval,
        Name,
        '+@cast_columns+'
FROM (
    SELECT  tStart,
            tEnd,
            ot.name,
            CAST(StartDate as date) as sDate, 
            Amt
    FROM #time_intervals t
    CROSS JOIN #Ordertypes ot 
    LEFT JOIN #Sale s
        ON CAST(s.StartDate as time) between t.tStart and t.tEnd and ot.ordertype_id = S.ordertype_id
) as p
PIVOT (
    SUM(Amt) FOR sDate IN ('+@columns+')
) as pvt
ORDER BY Name, tStart'

EXEC sp_executesql @sql

输出:

Interval    Name        2016-06-12  2016-06-13
00:00-01:00 DELIVERY    0.00        0.00
01:00-02:00 DELIVERY    0.00        0.00
02:00-03:00 DELIVERY    0.00        0.00
03:00-04:00 DELIVERY    0.00        0.00
04:00-05:00 DELIVERY    0.00        0.00
05:00-06:00 DELIVERY    0.00        0.00
06:00-07:00 DELIVERY    0.00        0.00
07:00-08:00 DELIVERY    0.00        0.00
08:00-09:00 DELIVERY    0.00        0.00
09:00-10:00 DELIVERY    0.00        0.00
10:00-11:00 DELIVERY    0.00        0.00
11:00-12:00 DELIVERY    0.00        0.00
12:00-13:00 DELIVERY    0.00        15.00
13:00-14:00 DELIVERY    0.00        0.00
...
09:00-10:00 DINE IN     0.00        0.00
10:00-11:00 DINE IN     30.00       0.00
11:00-12:00 DINE IN     0.00        0.00
...
11:00-12:00 TAKE OUT    0.00        0.00
12:00-13:00 TAKE OUT    50.00       0.00
13:00-14:00 TAKE OUT    0.00        0.00
14:00-15:00 TAKE OUT    0.00        0.00