在单行上显示“客户”及其所有订单日期

时间:2019-04-09 18:25:16

标签: sql snowflake-datawarehouse

我有一个客户表和一个订单表。我想将客户及其所有订单日期显示在一行上,而不是多行上。这是我所拥有的以及正在寻找的东西:

Picture of both tables, current results, what i'm looking for

获得结果的基本代码:

select customerid, name, orderdate
from customer_table c inner join
     order_table o
     on c.customerid = o.customerid 

5 个答案:

答案 0 :(得分:1)

这将最多发挥您无法在具有null的不同列上显示它的作用:

select customer_id,name,LISTAGG(orderdate, ', ') WITHIN GROUP (ORDER BY orderdate) 
from(select customerid, name, orderdate
from customer_table c inner join
order_table o
on c.customerid = o.customerid );

答案 1 :(得分:0)

如果使用MS SQL Server,请尝试以下操作:

 -- 1st, get the number of columns
declare @columnnumber int = 1
select @columnnumber = max(a.count)
from (
select c.cid,c.name, count(o.orderdate) as count
from 
customer_table c
join order_table o
on c.cid = o.cid
group by c.cid,c.name)a
print @columnnumber

-- Compose the column names for Pivot
declare @columnname varchar(max) = ''
declare @int int = 1
while @int <= @columnnumber
begin
set @columnname = @columnname + '[date' + cast(@int as varchar(10))+ '],'
set @int = @int + 1
end
set @columnname = '('+left(@columnname,len(@columnname)-1)+')'
print @columnname

--Pivot !!! + Dynamic SQL
declare @str varchar(max)
set @str = 
'SELECT *  
FROM  
(SELECT c.cid,c.name, o.orderdate,concat(''date'',row_number() over (partition by c.cid,c.name order by o.orderdate)) rnk
    FROM customer_table c
    join order_table  o
    on c.cid = o.cid) AS s
PIVOT  
(  
min(s.orderdate)  
FOR s.rnk IN '+ @columnname+
' ) AS PivotTable'
print @str

execute (@str)

请更改列名称。我使用cid作为您的客户ID。

输出:

cid name    date1       date2       date3 
12  John    2017-03-04  2017-05-26  2017-12-01
4   Nancy   2017-02-01  NULL        NULL

答案 2 :(得分:0)

您可以使用以下内容,因为您受12个订单限制的约束。如果您扩展到无上限的未知数量的订单,那么您将需要使用动态SQL,即使那样也很棘手,因为您还需要动态创建唯一的列名。

此查询按客户进行批处理并设置订单值。它们将按日期顺序排列,如果没有更多订单,则将其设置为NULL。它有点假设至少一个客户有12个订单。如果不是这种情况,您将获得所有NULL的列

IF OBJECT_ID('tempdb..#Results') IS NOT NULL DROP TABLE #Results
IF OBJECT_ID('tempdb..#sortedRows') IS NOT NULL DROP TABLE #SortedRows
DECLARE @CustomerList TABLE(CustomerID INT, RowNo INT); 
INSERT INTO @CustomerList SELECT DISTINCT CustomerID, ROW_NUMBER() OVER(ORDER BY CustomerID) RowNo FROM Customer_Table (NOLOCK)
DECLARE @Count INT = (SELECT COUNT(DISTINCT CustomerID) RowNumber FROM @CustomerList)
DECLARE @Counter INT = 0
DECLARE @CustToProcess INT
CREATE TABLE #Results(CustomerID INT, [Name] VARCHAR(50), OrderDate1 DATETIME, 
OrderDate2 DATETIME, OrderDate3 DATETIME, OrderDate4 DATETIME, OrderDate5 DATETIME, 
OrderDate6 DATETIME, OrderDate7 DATETIME, OrderDate8 DATETIME, OrderDate9 DATETIME, 
OrderDate10 DATETIME, OrderDate11 DATETIME, OrderDate12 DATETIME) 
INSERT INTO #Results(CustomerID, Name) SELECT DISTINCT CustomerID, Name FROM Customer_Table

SELECT ROW_NUMBER() OVER(PARTITION BY c.CustomerID ORDER BY OrderDate) RowNo,
c.CustomerID, c.Name, t.OrderDate  INTO #SortedRows
FROM Customer_Table c (NOLOCK) JOIN Order_Table t ON c.CustomerID = t.CustomerID 

WHILE @Counter < @Count
BEGIN
    SET @Counter += 1
    SET @CustToProcess = (SELECT CustomerID FROM @CustomerList WHERE RowNo = @Counter)
    PRINT @CustToProcess
    SELECT * INTO #RowsForProcessing FROM #SortedRows WHERE CustomerID = @CustToProcess
    UPDATE #Results SET OrderDate1 = (SELECT OrderDate FROM #RowsForProcessing WHERE Rowno = 1) WHERE CustomerID = @CustToProcess
    UPDATE #Results SET OrderDate2 = (SELECT OrderDate FROM #RowsForProcessing WHERE Rowno = 2) WHERE CustomerID = @CustToProcess
    UPDATE #Results SET OrderDate3 = (SELECT OrderDate FROM #RowsForProcessing WHERE Rowno = 3) WHERE CustomerID = @CustToProcess
    UPDATE #Results SET OrderDate4 = (SELECT OrderDate FROM #RowsForProcessing WHERE Rowno = 4) WHERE CustomerID = @CustToProcess
    UPDATE #Results SET OrderDate5 = (SELECT OrderDate FROM #RowsForProcessing WHERE Rowno = 5) WHERE CustomerID = @CustToProcess
    UPDATE #Results SET OrderDate6 = (SELECT OrderDate FROM #RowsForProcessing WHERE Rowno = 6) WHERE CustomerID = @CustToProcess
    UPDATE #Results SET OrderDate7 = (SELECT OrderDate FROM #RowsForProcessing WHERE Rowno = 7) WHERE CustomerID = @CustToProcess
    UPDATE #Results SET OrderDate8 = (SELECT OrderDate FROM #RowsForProcessing WHERE Rowno = 8) WHERE CustomerID = @CustToProcess
    UPDATE #Results SET OrderDate9 = (SELECT OrderDate FROM #RowsForProcessing WHERE Rowno = 9) WHERE CustomerID = @CustToProcess
    UPDATE #Results SET OrderDate10 = (SELECT OrderDate FROM #RowsForProcessing WHERE Rowno = 10) WHERE CustomerID = @CustToProcess
    UPDATE #Results SET OrderDate11 = (SELECT OrderDate FROM #RowsForProcessing WHERE Rowno = 11) WHERE CustomerID = @CustToProcess
    UPDATE #Results SET OrderDate12 = (SELECT OrderDate FROM #RowsForProcessing WHERE Rowno = 12) WHERE CustomerID = @CustToProcess

    DROP Table #RowsForProcessing
END
SELECT * FROM #Results

答案 3 :(得分:0)

就像其他人说的那样,原则上(纯SQL)不可能不知道单个客户有多少订单就生成此信息。

我喜欢@ nikhil-sugandh的回答,如果您可以将所有订单用逗号分隔在一个列中,那么效果很好。

如果您坚持要有多列,则可以通过用LISTAGG替换ARRAY_AGG并对其进行后处理来建立答案。它将比例如带有多个联接的建议解决方案。您还可以使用ARRAY_SLICE处理订单数量超出您准备的情况。

示例(注意,我添加了一个额外的订单,以演示如何处理超出预期的订单

create or replace table customer_table(customerId int, name varchar) 
as select * from values
(12,'John'),(4,'Nancy');

create or replace table order_table(orderId int, customerId int, orderDate date) 
as select * from values
(1,12,'3/4/2017'),(2,12,'5/26/2017'),(3,12,'12/1/2017'),(4,4,'2/1/2017'),(5,12,'1/1/2019');

with subq as (
  select c.customerid, name, 
    array_agg(orderdate) within group (order by orderdate) as orders
  from customer_table c 
  inner join order_table o on c.customerid = o.customerid 
  group by c.customerid, c.name
) 
select customerid, name, 
  orders[0]::date AS order1, orders[1]::date AS order2,
  array_to_string(array_slice(orders, 2, 999), ' , ') AS overflow 
from subq;

------------+-------+------------+------------+-------------------------+
 CUSTOMERID | NAME  |   ORDER1   |   ORDER2   |        OVERFLOW         |
------------+-------+------------+------------+-------------------------+
 4          | Nancy | 2017-02-01 | [NULL]     |                         |
 12         | John  | 2017-03-04 | 2017-05-26 | 2017-12-01 , 2019-01-01 |
------------+-------+------------+------------+-------------------------+

答案 4 :(得分:-1)

首先创建一个这样的视图:

create view order_view as 
select 
count(*) over (partition by customerId order by orderDate) as ord,
CustomerId,
orderdate
 from order_table 

然后您可以使用以下查询:

 select c.customerid, 
 o1.orderdate,
 o2.orderdate
 o3.orderdate
 .
 .
 .
 o12.orderdate
from customer_table c 
left join  order_view  o1
     on c.customerid = o1.customerid and ord = 1 
left join  order_view  o2
     on c.customerid = o2.customerid and ord = 2 
left join  order_view  o3
     on c.customerid = o3.customerid and ord = 3
.
.
.     
left join  order_view  o12
     on c.customerid = o12.customerid and ord = 12