构造二进制值表,指示另一个表中是否存在条目

时间:2016-09-19 18:13:28

标签: sql sql-server pivot associations case

我有几个表包含不同项目的订单信息。客户可能会在不同的表格中多次出现。这些项目是表格所特有的。我想创建一个新表格,显示客户在特定年份购买的所有商品。每个项目应该有一列,二进制值表示客户是否购买了该年份的项目。

换句话说,我想将列出单项订单的所有表格(例如,客户1在2007年11月购买的项目a和2007年5月的项目c)转换为年度交易(例如,客户1的交易为2007年的{ a,c}或[1,0,1,0])。我想将单个订单分成年度交易,以便我可以挖掘关联规则。

最小工作示例:

表1包含项目a和b的订单。表2包含项目c和d的订单。

CREATE TABLE table1
(
orderId INT,
customerId INT,
orderDate DATE,
item VARCHAR(1)
);

CREATE TABLE table2
(
orderId INT,
customerId INT,
orderDate DATE,
item VARCHAR(1)
);

INSERT INTO table1 (orderId, customerId, orderDate, item)
VALUES 
('1', '1', '2007-11-11', 'a'),
('2', '2', '2008-3-20', 'b'),
('3', '3','2009-7-11', 'a');

INSERT INTO table2 (orderId, customerId, orderDate, item)
VALUES 
('4', '2', '2008-1-1', 'c'), 
('5', '1', '2007-5-15', 'c'), 
('6', '1', '2009-2-2', 'd');

我正在使用联合组合表格,因为即使订单不同,某些订单ID也可能会重叠。

SELECT * 
INTO #table3
FROM
(
SELECT *
FROM table1 
UNION ALL 
SELECT * 
FROM table2
) a;

这是尝试解决方案,但它不是很优雅。更重要的是,它不会根据需要将案例陈述应用于每一年。

SELECT customerId, 
DATEPART(YEAR, orderDate) as orderYear,
    CASE
        WHEN customerId IN (
            SELECT DISTINCT customerId
            FROM #table3
            WHERE item = 'a')
            THEN 1
        ELSE 0 
    END AS itemA,
    CASE
        WHEN customerId IN (
            SELECT DISTINCT customerId
            FROM #table3
            WHERE item = 'b')
            THEN 1
        ELSE 0 
    END AS itemB,
    CASE
        WHEN customerId IN (
            SELECT DISTINCT customerId
            FROM #table3
            WHERE item = 'c')
            THEN 1
        ELSE 0 
    END AS itemC,
    CASE
        WHEN customerId IN (
            SELECT DISTINCT customerId
            FROM #table3
            WHERE item = 'd')
            THEN 1
        ELSE 0 
    END AS itemD
FROM #table3
ORDER BY customerId, orderDate;

期望的结果如下:

CREATE TABLE desiredResult
(
customerId INT,
orderYear INT,
itemA INT,
itemB INT,
itemC INT,
itemD INT
);

INSERT INTO desiredResult (customerId, orderYear, itemA, itemB, itemC, itemD)
VALUES 
('1', '2007', '1', '0', '1', '0'), 
('1', '2009', '0', '0', '0', '1'), 
('2', '2008', '0', '1', '1', '0'),
('3', '2009', '1', '0', '0', '0');

有没有更简单的方法来获得我想要的结果?这是PIVOT可能有用的东西吗?

1 个答案:

答案 0 :(得分:1)

我会使用条件聚合来做到这一点:

SELECT customerId, OrderYear,
       MAX(CASE WHEN item = 'a' THEN 1 ELSE 0 END) as itemA,
       MAX(CASE WHEN item = 'b' THEN 1 ELSE 0 END) as itemB,
       MAX(CASE WHEN item = 'c' THEN 1 ELSE 0 END) as itemC,
       MAX(CASE WHEN item = 'd' THEN 1 ELSE 0 END) as itemD
FROM ((SELECT customerId, year(OrderDate) as OrderYear, item FROM table1
      ) union all
      (SELECT customerId, year(OrderDate) as OrderYear, item FROM table2
      )
     ) t
GROUP BY customerId, orderYear;

这也消除了对临时表的需求。