如何获取Sql Temp Table使用不在表中的列值进行连接,替换为0

时间:2017-11-15 20:37:50

标签: sql sql-server

我想通过month_year列和prod_id将5个临时表组合成一个新的临时表。如果列不是prod_id或month_year且值不可用,我希望该列的值(例如job_amt或received_qty)为0。

#tmp_spoilt_good_job_amt
month_year  job_amt     spoil   good    prod_id
07-2017         40      10        20    2
08-2017         827     0         210   3
09-2017         27      1         27    2
09-2017         732     22        345   3
10-2017         50      0         6     2
10-2017         1130    55        50    3
11-2017         300     0         0     4

#tmp_received_qty
month_year  received_qty    prod_id
 08-2017    32                 2
 08-2017    2500               3
 09-2017    2200               2
 11-2017    2500               4

#tmp_purchase_qty
month_year  purchase_qty    prod_id
 09-2017    11                 2

#tmp_opening_balance 
month_year  opening_balance   prod_id
08-2017              32         2
08-2017             2500        3
09-2017               22        2
09-2017             2300        3
10-2017             2163        2
10-2017             2023        3
11-2017             2500        4

#tmp_closing_balance
month_year  closing_balance     prod_id
08-2017         2300                3
08-2017         32                  2
09-2017         2213                2
09-2017         1998                3
10-2017         1687                3
10-2017         2163                2
11-2017         2400                4

我尝试了一些内连接但是值重复或有些没有反映。我可以用什么查询来组合这些?

我正在寻找以下输出:enter image description here

4 个答案:

答案 0 :(得分:2)

CREATE TABLE #table_with_all_months_prod_ids_using_cross_join (month_year, prod_id) 
GO

INSERT #table_with_all_months_prod_ids_using_cross_join 
SELECT t1.month_year, t2.prod_id 
FROM monthyeartable t1 
CROSS JOIN prodidtable t2

SELECT DISTINCT t0.month_year, t0.prod_id, ISNULL(t1.job_amt,0), ISNULL(t1.spoil,0), ISNULL(t1.good,0), ISNULL(t2.received_qty,0), ISNULL(t3.purchase_qty,0), ISNULL(t4.opening_balance,0), ISNULL(t5.closing_balance,0)     
        FROM #table_with_all_months_prod_ids_using_cross_join t0
        LEFT JOIN #tmp_spoilt_good_job_amt t1 ON t0.month_year = t1.month_year AND t0.prod_id = t1.prod_id
        LEFT JOIN #tmp_received_qty t2 ON t0.month_year = t2.month_year AND t0.prod_id = t2.prod_id
        LEFT JOIN #tmp_purchase_qty t3 ON t0.month_year = t3.month_year AND t0.prod_id = t3.prod_id
        LEFT JOIN #tmp_opening_balance t4 ON t0.month_year = t4.month_year AND t0.prod_id = t4.prod_id
        LEFT JOIN #tmp_closing_balance t5 ON t0.month_year = t5.month_year AND t0.prod_id = t5.prod_id 
WHERE NOT (t1.job_amt IS NULL AND t1.spoil IS NULL AND t1.good IS NULL AND t2.received_qty IS NULL AND t3.purchase_qty IS NULL AND t4.opening_balance IS NULL AND t5.closing_balance IS NULL) 

答案 1 :(得分:1)

因此,这种关系具有非常周的性能,首先,最好更改表结构以及与数据库中的填充数据相关的所有其他事物。

无论如何,这个query是根据当前数据结构为您当前的需求创建的,如果您使用此query或将其划分为某些views,也许可以提高效果:

SELECT CASE WHEN ISNULL(srpo.month_year , '-1') <> '-1' THEN srpo.month_year 
            WHEN ISNULL(c.month_year , '-1') <> '-1' THEN c.month_year 
       END AS month_year,
       CASE WHEN ISNULL(srpo.prod_id, -1) <> -1 THEN srpo.prod_id 
            WHEN ISNULL (c.prod_id, -1) <> -1 THEN c.prod_id 
       END AS prod_id, 
       CASE WHEN ISNULL(c.closing_balance, -1) = -1 THEN 0 else c.closing_balance END AS closing_balance,
       srpo.job_amt,srpo.spoil,srpo.good ,srpo.received_qty,srpo.purchase_qty, srpo.opening_balance
FROM   #tmp_closing_balance AS c FULL OUTER JOIN

(SELECT CASE WHEN ISNULL(srp.month_year , '-1') <> '-1' THEN srp.month_year 
            WHEN ISNULL(o.month_year , '-1') <> '-1' THEN o.month_year 
       END AS month_year,
       CASE WHEN ISNULL(srp.prod_id, -1) <> -1 THEN srp.prod_id 
            WHEN ISNULL (o.prod_id, -1) <> -1 THEN o.prod_id 
       END AS prod_id, 
       CASE WHEN ISNULL(o.opening_balance, -1) = -1 THEN 0 else o.opening_balance END AS opening_balance,
       srp.job_amt,srp.spoil,srp.good ,srp.received_qty,srp.purchase_qty
FROM   #tmp_opening_balance AS o FULL OUTER JOIN

(SELECT CASE WHEN ISNULL(sr.month_year , '-1') <> '-1' THEN sr.month_year 
            WHEN ISNULL(p.month_year , '-1') <> '-1' THEN p.month_year 
       END AS month_year,
       CASE WHEN ISNULL(sr.prod_id, -1) <> -1 THEN sr.prod_id 
            WHEN ISNULL (p.prod_id, -1) <> -1 THEN p.prod_id 
       END AS prod_id, 
       CASE WHEN ISNULL(p.purchase_qty, -1) = -1 THEN 0 else p.purchase_qty END AS purchase_qty,
       sr.job_amt,sr.spoil,sr.good ,sr.received_qty 
FROM #tmp_purchase_qty AS p FULL OUTER JOIN 
     (SELECT CASE WHEN ISNULL(s.month_year , '-1') <> '-1' THEN s.month_year 
            WHEN ISNULL(r.month_year , '-1') <> '-1' THEN r.month_year 
       END AS month_year,
       CASE WHEN ISNULL(s.prod_id, -1) <> -1 THEN s.prod_id 
            WHEN ISNULL (r.prod_id, -1) <> -1 THEN r.prod_id 
       END AS prod_id,
       CASE WHEN ISNULL(s.job_amt, -1) = -1 THEN 0 else s.job_amt END AS job_amt,
       CASE WHEN ISNULL(s.spoil, -1) = -1 THEN 0 else s.spoil END AS spoil,
       CASE WHEN ISNULL(s.good, -1) = -1 THEN 0 else s.good END AS good,
       CASE WHEN ISNULL(r.received_qty, -1) = -1 THEN 0 else r.received_qty END AS received_qty
FROM #tmp_spoilt_good_job_amt AS s FULL OUTER JOIN  
     #tmp_received_qty AS r ON s.prod_id = r.prod_id AND
                              LTRIM(rtrim(s.month_year)) = LTRIM(rtrim(r.month_year))) AS sr ON
     sr.prod_id = p.prod_id AND LTRIM(rtrim(sr.month_year)) = LTRIM(rtrim(p.month_year)) ) AS srp ON
     srp.prod_id = o.prod_id AND LTRIM(rtrim(srp.month_year)) = LTRIM(rtrim(o.month_year))) AS srpo ON
     srpo.prod_id = c.prod_id AND LTRIM(rtrim(srpo.month_year)) = LTRIM(rtrim(c.month_year))

我对FULL OUTER JOIN的所有部分使用query,因为您提到过,可能所有表都有键列的可能值(month_yearprod_id)。

答案 2 :(得分:1)

首先,如果你有这5个临时表,这可能意味着在源表级别有更好的方法可以做到这一点!但是因为你问你最重要的问题是组合它们是因为没有一个表包含每个month_yearprod_id的组合。所以你必须创建它。我选择完整的方式是:

  1. 创建一个Tally表(作为公用表表达式[CTE])以供使用 生成month_year表
  2. 通过合并临时表中的所有不同prod_id来创建产品CTE
  3. 创建MonthYearInputs CTE以确定代表的最大和最小月份
  4. 生成MonthYear CTE以容纳MIN和&amp;之间的每个可能的month_year组合。数据中包含MAX年数
  5. 然后在月份年份和月份之间加入一个cartisean(CROSS)加入。产品ctes为您提供LEFT JOIN其他表格的所有组合。
  6. 只需输入where语句即可删除所有表中没有值的行,并使用ISNULL()COALESCE()将空值设为0。
  7. 以下是一个工作示例:http://rextester.com/MCEO96178

    ;WITH cteTen AS (
        SELECT n FROM (VALUES (0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) t(n)
    )
    
    , cteTally AS (
        SELECT
           n = ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
        FROM
           cteTen t1
           CROSS JOIN cteTen t2 --hundreds
           CROSS JOIN cteTen t3 --thousands
           --keep cross joining if need more than 1000 month
    )
    
    , cteProducts AS (
        SELECT DISTINCT prod_id FROM #tmp_spoilt_good_job_amt
        UNION
        SELECT DISTINCT prod_id FROM #tmp_received_qty
        UNION
        SELECT DISTINCT prod_id FROM #tmp_purchase_qty
        UNION
        SELECT DISTINCT prod_id FROM #tmp_opening_balance
        UNION
        SELECT DISTINCT prod_id FROM #tmp_closing_balance
    )
    
    , cteInputMonthYears AS (
        SELECT DISTINCT month_year FROM #tmp_spoilt_good_job_amt
        UNION
        SELECT DISTINCT month_year FROM #tmp_received_qty
        UNION
        SELECT DISTINCT month_year FROM #tmp_purchase_qty
        UNION
        SELECT DISTINCT month_year FROM #tmp_opening_balance
        UNION
        SELECT DISTINCT month_year FROM #tmp_closing_balance
    )
    
    , cteMaxMinMonthYears AS (
        SELECT
           MinMonthYear =  CAST(STUFF(MIN(month_year),3,0,'-01') AS DATETIME)
           ,MonthsDiff = DATEDIFF(MONTH,CAST(STUFF(MIN(month_year),3,0,'-01') AS DATETIME),CAST(STUFF(MAX(month_year),3,0,'-01') AS DATETIME)) + 1
        FROM
           cteInputMonthYears
    )
    
    , cteMonthYears AS (
        SELECT
           month_year = FORMAT(DATEADD(MONTH, t.n - 1, m.MinMonthYear),'MM-yyyy')
        FROM
           cteMaxMinMonthYears m
           INNER JOIN cteTally t
           ON m.MonthsDiff >= t.n
    )
    
    SELECT
        my.month_year
        ,job_amt = ISNULL(ja.job_amt,0)
        ,spoil = ISNULL(ja.spoil,0)
        ,good = ISNULL(ja.good,0)
        ,p.prod_id
        ,received_qty = ISNULL(r.received_qty,0)
        ,purchase_qty = ISNULL(pur.purchase_qty,0)
        ,opening_balance = ISNULL(o.opening_balance,0)
        ,closing_balance = ISNULL(c.closing_balance,0)
    FROM
        cteMonthYears my
        CROSS JOIN cteProducts p
        LEFT JOIN #tmp_spoilt_good_job_amt ja
        ON my.month_year = ja.month_year
        AND p.prod_id = ja.prod_id
        LEFT JOIN #tmp_received_qty r
        ON my.month_year = r.month_year
        AND p.prod_id = r.prod_id
        LEFT JOIN #tmp_purchase_qty pur
        ON my.month_year = pur.month_year
        AND p.prod_id = pur.prod_id
        LEFT JOIN #tmp_opening_balance o
        ON my.month_year = o.month_year
        AND p.prod_id = o.prod_id
        LEFT JOIN #tmp_closing_balance c
        ON my.month_year = c.month_year
        AND p.prod_id = c.prod_id
    WHERE
        NOT(ja.month_year IS NULL 
           AND r.month_year IS NULL
           AND pur.month_year IS NULL
           AND o.month_year IS NULL
           AND o.month_year IS NULL
           AND c.month_year IS NULL)
    ORDER BY
        my.month_year
        ,p.prod_id
    

答案 3 :(得分:1)

就我个人而言,我认为你应该使用@ influent的建议:派生一个模板表,你可以将你想要的值留下来。

如果您没有准确推导出这样的模板表所需的逻辑或数据,还有另一种选择。
  1.使用虚拟0值填充每个表,以便它们都具有相同的字段
  2. UNION所有表格在一起   3. GROUP所有结果返回到每个产品每月一行

WITH
    padded_combined
AS
(

    SELECT month_year, prod_id, job_amt, spoil, good, 0 AS received_qty, 0 AS purchase_qty, 0 AS opening_balance, 0 AS closing_balance FROM #tmp_spoilt_good_job_amt
    UNION ALL
    SELECT month_year, prod_id, 0, 0, 0, received_qty, 0, 0, 0 FROM #tmp_received_qty
    UNION ALL
    SELECT month_year, prod_id, 0, 0, 0, 0, purchase_qty, 0, 0 FROM #tmp_purchase_qty
    UNION ALL
    SELECT month_year, prod_id, 0, 0, 0, 0, 0, opening_balance, 0 FROM #tmp_opening_balance
    UNION ALL
    SELECT month_year, prod_id, 0, 0, 0, 0, 0, 0, closing_balance FROM #tmp_closing_balance
)
SELECT
    month_year,
    prod_id,
    SUM(job_amt)            AS job_amt,
    SUM(spoil)              AS spoil,
    SUM(good)               AS good,
    SUM(received_qty)       AS received_qty,
    SUM(purchase_qty)       AS purchase_qty,
    SUM(opening_balance)    AS opening_balance,
    SUM(closing_balance)    AS closing_balance
FROM
    padded_combined
GROUP BY
    month_year,
    prod_id
ORDER BY
    month_year,
    prod_id