簡體   English   中英

SQL中的自引用CASE WHEN子句

[英]Self-referential CASE WHEN clause in SQL

我正在嘗試將一些格式不佳的數據遷移到數據庫中。 數據來自CSV,並首先加載到所有varchar列的臨時表中(因為我在此階段無法強制執行類型安全)。

數據可能看起來像

COL1     | COL2 | COL3
Name 1   |      |     
2/11/16  | $350 | $230
2/12/16  | $420 | $387
2/13/16  | $435 | $727
Name 2   |      |     
2/11/16  | $121 | $144
2/12/16  | $243 | $658
2/13/16  | $453 | $214

第一個列是公司名稱作為偽標題的混合,以及列2和3數據相關的日期。 我想通過創建“品牌”列來開始轉換數據 - 其中,如果Col2為NULL,'StoreBrand'是Col1的值,否則是前一行的StoreBrand。 像:

COL1     | COL2 | COL3 | StoreBrand
Name 1   |      |      | Name 1
2/11/16  | $350 | $230 | Name 1
2/12/16  | $420 | $387 | Name 1
2/13/16  | $435 | $727 | Name 1
Name 2   |      |      | Name 2
2/11/16  | $121 | $144 | Name 2
2/12/16  | $243 | $658 | Name 2
2/13/16  | $453 | $214 | Name 2

我寫了這個:

SELECT 
    t.*,
    CASE
        WHEN t.COL2 IS NULL THEN COL1
        ELSE                     LAG(StoreBrand) OVER ()
    END AS StoreBrand
FROM
(
    SELECT
        ROW_NUMBER() OVER () AS i,
        *
    FROM
        Staging_Data
) t;

但是數據庫(在這種情況下是postgres,但我們正在考慮替代方案,因此最優選的答案是最優選的) LAG(StoreBrand)上的choke因為那是我正在創建的派生列。 調用LAG(Col1)僅填充第一行的實際數據:

COL1     | COL2 | COL3 | StoreBrand
Name 1   |      |      | Name 1
2/11/16  | $350 | $230 | Name 1
2/12/16  | $420 | $387 | 2/11/16
2/13/16  | $435 | $727 | 2/12/16
Name 2   |      |      | Name 2
2/11/16  | $121 | $144 | Name 2
2/12/16  | $243 | $658 | 2/11/16
2/13/16  | $453 | $214 | 2/12/16

我的目標是StoreBrand列,它是下一個品牌名稱之前所有日期值的COL1的第一個值:

COL1     | COL2 | COL3 | StoreBrand
Name 1   |      |      | Name 1
2/11/16  | $350 | $230 | Name 1
2/12/16  | $420 | $387 | Name 1
2/13/16  | $435 | $727 | Name 1
Name 2   |      |      | Name 2
2/11/16  | $121 | $144 | Name 2
2/12/16  | $243 | $658 | Name 2
2/13/16  | $453 | $214 | Name 2

當Col2和Col3為空時,StoreBrand的值無關緊要 - 該行將作為轉換過程的一部分被刪除。 重要的是將數據行(即具有日期的行)與其品牌相關聯。

有沒有辦法引用我缺少的列的先前值?

編輯通過搜索引擎找到此問題的人:

訣竅是使用WITH允許在幾個地方( 鏈接 )使用臨時結果。


我認為這樣做你想要的並同時丟棄空行(如果你願意)。 我們基本上在我們目前正在查看的行之前選擇所有品牌,如果它與當前行之間沒有“品牌行”,那么我們接受它。

WITH t AS
   (SELECT
      ROW_NUMBER() OVER () AS i,
      *
   FROM
      Staging_Data
   )
SELECT
   a.COL1,
   a.COL2,
   a.COL3,
   (SELECT b.COL1 FROM t b WHERE b.COL2 IS NULL AND b.i <= a.i AND NOT EXISTS(
      SELECT * FROM t c WHERE c.COL2 IS NULL AND c.i <= a.i AND c.i > b.i)
   ) StoreBrand
FROM
   t a
WHERE -- I don't think you need those rows? Otherwise remove it.
   a.COL2 IS NOT NULL

這可能有點令人困惑。 t是我們with您的查詢定義的臨時表。 並且abct別名。 我們也可以編寫FROM t AS a來使其更加明顯。

我想我明白你想要什么。 從技術上講,你想在lag()上使用ignore nulls選項,所以它看起來像這樣:

select lag(case when col1 not like '%/%/%' then col1 end ignore nulls) over (order by linenumber) as brandname

唯一的問題? Postgres不支持ignore nulls

但是,你可以使用子查詢做同樣的事情。 我們的想法是為每個組分配一個分組標識符。 這是有效品牌名稱的累積計數。 然后一個簡單的max()聚合工作:

select t.*,
       max(case when col1 not like '%/%/%' then col1 end) over (partition by grp) as brand
from (select t.*,
             sum(case when col1 not like '%/%/%' then 1 end) over
                 (order by linenumber) as grp
      from t
     );

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM