将多个数据集合并为一个查询

时间:2013-12-04 18:26:40

标签: sql sql-server sql-server-2008 tsql sql-server-2008-r2

我有多个查询:

1)    select Year , Month, Sum(Stores) from ABC ;

2)     select Year, Month , Sum(SalesStores) from DEF ; 

3)     slect Year, Month, Sum(Products) from FGH;

我想要一个结果:

Year, Month , Sum(Stores), Sum(SalesStores), Sum(Products)

我尝试使用类似这样的查询完全外部联接:

SELECT ISNULL(x.[Year], y.[Year]) AS [Year],
ISNULL(x.[Month], y.[Month]) AS [Month],
x.Sum_Stores,
y.Sum_SalesStores,
z.Sum_products
FROM (select Year , Month, Sum(Stores) AS Sum_Stores from ABC ... GROUP BY [Month]) AS x
FULL OUTER JOIN (select Year, Month , Sum(SalesStores) AS Sum_SalesStores from DEF ... GROUP BY [Month]) AS y
    ON x.[Year] = y.[Year] AND x.[Month] = y.[Month]
FULL OUTER JOIN (select Year, Month , Sum(products) AS Sum_products from FGH ... GROUP BY [Month])  AS z
ON y.[Year] = z.[Year] AND y.[Month] = z.[Month]

问题在于,ABC只有几个月的数据,DEF有不同月份的数据,FGH在不同月份也有数据。

当我运行上面的查询时,我得到了很多空值和0。

任何人都可以纠正我对查询的错误或告诉我一个适合我案例的解决方案。

6 个答案:

答案 0 :(得分:1)

以下是获取此信息的另一种方法。此示例有一个简短的设置来演示此解决方案的实际效果。

CREATE TABLE #ABC([Year] INT, [Month] INT, Stores INT);
CREATE TABLE #DEF([Year] INT, [Month] INT, SalesStores INT);
CREATE TABLE #GHI([Year] INT, [Month] INT, Products INT);

INSERT #ABC VALUES (2013,1,1);
INSERT #ABC VALUES (2013,1,2);
INSERT #ABC VALUES (2013,2,3);

INSERT #DEF VALUES (2013,1,4);
INSERT #DEF VALUES (2013,1,5);
INSERT #DEF VALUES (2013,2,6);

INSERT #GHI VALUES (2013,1,7);
INSERT #GHI VALUES (2013,1,8);
INSERT #GHI VALUES (2013,2,9);
INSERT #GHI VALUES (2013,3,10);


SELECT
     T.[Year]
    ,T.[Month]
    -- select the sum for each year/month combination using a correlated subquery (each result from the main query causes another data retrieval operation to be run)
    ,(SELECT SUM(Stores) FROM #ABC WHERE [Year]=T.[Year] AND [Month]=T.[Month]) AS [Sum_Stores]
    ,(SELECT SUM(SalesStores) FROM #DEF WHERE [Year]=T.[Year] AND [Month]=T.[Month]) AS [Sum_SalesStores]
    ,(SELECT SUM(Products) FROM #GHI WHERE [Year]=T.[Year] AND [Month]=T.[Month]) AS [Sum_Products]
FROM (
    -- this selects a list of all possible dates.
    SELECT [Year],[Month] FROM #ABC
    UNION
    SELECT [Year],[Month] FROM #DEF
    UNION
    SELECT [Year],[Month] FROM #GHI
) AS T;

编辑: 这可以按照要求包含在参数化存储过程中:

-- Call proc like this

--EXEC [getMyReport]; -- params are not required, these will default to NULL if not specified.
--EXEC [getMyReport] @Year=2013; -- all 2013 data, all months
--EXEC [getMyReport] @Month=1; -- all January data, from all years
--EXEC [getMyReport] @Year=2013, @Month=2; -- Feb 2013 data only.

CREATE PROCEDURE [dbo].[getMyReport]
     @Year INT = NULL -- default to NULL, this makes the param optional when you exec the procedure.
    ,@Month INT = NULL
AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;

    SELECT
         T.[Year]
        ,T.[Month]
        -- select the sum for each year/month combination using a correlated subquery (each result from the main query causes another data retrieval operation to be run)
        ,(SELECT SUM(Stores) FROM #ABC WHERE [Year]=T.[Year] AND [Month]=T.[Month]) AS [Sum_Stores]
        ,(SELECT SUM(SalesStores) FROM #DEF WHERE [Year]=T.[Year] AND [Month]=T.[Month]) AS [Sum_SalesStores]
        ,(SELECT SUM(Products) FROM #GHI WHERE [Year]=T.[Year] AND [Month]=T.[Month]) AS [Sum_Products]
    FROM (
        -- this selects a list of all possible dates.
        SELECT [Year],[Month] FROM #ABC
        UNION
        SELECT [Year],[Month] FROM #DEF
        UNION
        SELECT [Year],[Month] FROM #GHI
    ) AS T
    WHERE
        -- if the param IS NULL, then it will not apply filtering
        -- if the param is specified, then it will filter by year or month
        (@Year IS NULL OR T.[Year]=@Year)
        AND
        (@Month IS NULL OR T.[Month]=@Month)
    ;
END
GO

答案 1 :(得分:0)

   select x,y,z from tableA
   UNION
   select x,y,z from tableB
   UNION
   select x,y,z from tableC

答案 2 :(得分:0)

使用union alls和group by来代替:

    select year, month, sum(stores) as sumStores, sum(salesStores) as sumSalesStores, sum(products) as sumProducts
    from (
        select year, month, stores, salesStores = null, products = null
        from ABC

        union all

        select year, month, stores = null, salesStores, products = null
        from DEF

        union all

        select year, month, stores = null, salesStores = null, products
        from FGH
    ) x
    group by year, month;

答案 3 :(得分:0)

使用类似的方法可能更清楚: -

select 
    Year, 
    Month, 
    sum(Stores) as Stores, 
    sum(SalesStores) as SalesStores, 
    sum(products) as products
from (
    select Year, Month, Stores, 0.00 as SalesStores, 0.00 as products
    from ABC ...
    union all
    select Year, Month, 0 as Stores, SalesStores, 0 as products
    from DEF ...
    union all
    select Year, Month, 0 as Stores, 0 as SalesStores, products
    from FGH ...
) source
group by Year, Month

派生表中的第一个select语句定义了它的结构 - 您可能需要cast该语句中的占位符列,以获得正确精度和比例的类型,以允许后续数据{ {1}}不会失去任何精确度。

答案 4 :(得分:0)

以下是使用完整联接的答案:

select
     coalesce(ABC.Year,DEF.Year,FGH.Year) as Year
    ,coalesce(ABC.Month,DEF.Month,FGH.Month) as Month
    ,ABC.Stores
    ,DEF.SalesStores
    ,FGH.Products
from (
    select Year , Month, Sum(Stores) as Stores from ABC group by Year , Month
) ABC
full join (
    select Year, Month , Sum(SalesStores) as SalesStores from DEF group by Year , Month
) DEF
    on DEF.year = ABC.Year
    and DEF.Month = ABC.Month
full join (
    select Year, Month, Sum(Products) as Products from FGH group by Year , Month
) FGH
    on (FGH.year = ABC.Year
    and FGH.Month = ABC.Month)
    or (FGH.Month = DEF.Year
    and FGH.Month = DEF.Month)

SQL Fiddle Demo

答案 5 :(得分:0)

您可以将多个集合合并为:

SELECT Year, Month, 'Stores' AS Src, Stores AS Value FROM ABC
UNION ALL
SELECT Year, Month, 'SalesStores',   SalesStores     FROM DEF
UNION ALL
SELECT Year, Month, 'Products',      Products        FROM FGH

然后PIVOT他们聚合:

SELECT
  Year,
  Month,
  Stores,
  SalesStores,
  Products
FROM (
  SELECT Year, Month, 'Stores',      Stores      FROM ABC
  UNION ALL
  SELECT Year, Month, 'SalesStores', SalesStores FROM DEF
  UNION ALL
  SELECT Year, Month, 'Products',    Products    FROM FGH
) AS s (Year, Month, Src, Value)
PIVOT (
  SUM(Value) FOR Src IN (Stores, SalesStores, Products)
) AS p
;

或者首先聚合结果可能更有效,然后联合聚合集,然后PIVOT:

SELECT
  Year,
  Month,
  Stores,
  SalesStores,
  Products
FROM (
  SELECT Year, Month, 'Stores',      SUM(Stores)      FROM ABC
  UNION ALL
  SELECT Year, Month, 'SalesStores', SUM(SalesStores) FROM DEF
  UNION ALL
  SELECT Year, Month, 'Products',    SUM(Products)    FROM FGH
) AS s (Year, Month, Src, Value)
PIVOT (
  MAX(Value) FOR Src IN (Stores, SalesStores, Products)
) AS p
;

由于PIVOT语法需要使用聚合函数,我们可以使用一个只保留已聚合值的函数(在本例中为MAX)。