2

SQL Server 2008 R2 のテーブルから次の行があります

+-------------------------------------------+
|  ID          EntryType dt         price   |
+-------------------------------------------+
| 14          4         2012-11-07 0.025000 |
| 16          5         2012-11-07 0.026000 |
| 18          6         2012-11-07 0.026000 |
| 20          7         2012-11-07 0.026000 |
+-------------------------------------------+

私がしたいのは、EntryType に基づいて行を広げることです (EntryType は変更されません)。

For EntryType = 4 (1 row)
For EntryType = 5 (2 row)
For EntryType = 6 (3 row)
For EntryType = 7 (9 row)

dt フィールドは (月間隔で) 増加するため、出力は次のようになります。

+-----------+-----------+-------+
| EntryType |    dt     | Price |
+-----------+-----------+-------+
|         4 | 11/7/2012 | 0.024 |
|         5 | 12/7/2012 | 0.025 |
|         5 | 1/7/2013  | 0.025 |
|         6 | 2/7/2013  | 0.026 |
|         6 | 3/7/2013  | 0.026 |
|         6 | 4/7/2013  | 0.026 |
|         7 | 5/7/2013  | 0.027 |
|         7 | 6/7/2013  | 0.027 |
|         7 | 7/7/2013  | 0.027 |
|         7 | 8/7/2013  | 0.027 |
|         7 | 9/7/2013  | 0.027 |
|         7 | 10/7/2013 | 0.027 |
|         7 | 11/7/2013 | 0.027 |
|         7 | 12/7/2013 | 0.027 |
|         7 | 1/7/2014  | 0.027 |
+-----------+-----------+-------+

CTEとSQLでそれを行うことは可能ですか?

4

3 に答える 3

3

再帰CTEでこれを行う方法は次のとおりです。

;with RecordCounts as (
    -- Establish row counts for each EntryType
    select 4 as EntryType, 1 as RecordCount
    union all select 5, 2
    union all select 6, 3
    union all select 7, 9
), PricesCte as (
    -- Get initial set of records
    select ID, p.EntryType, (select min(dt) from MyTable) as dt, price, 1 as RecordNum
    from MyTable p
        join RecordCounts c on p.EntryType = c.EntryType -- Only get rows where we've established a RecordCount
    -- Add records recursively according to RecordCount
    union all
    select ID, p.EntryType, dt, price, RecordNum + 1
    from PricesCte p
        join RecordCounts c on p.EntryType = c.EntryType
    where RecordNum + 1 <= c.RecordCount
)
select EntryType,
    dateadd(mm, row_number() over (order by EntryType, ID) - 1, dt) as dt,
    price
from PricesCTE
order by EntryType
option (maxrecursion 0) -- Infinite recursion, default limit is 100

これがこの作品を示すSqlFiddleです。

いくつかのこと:

  • レコードの数が増えるにつれて、レコードを乗算するために再帰するよりも、 Tallyテーブルを使用した方がパフォーマンスが向上する可能性があると思います。Tallyテーブルと相互結合し、where句でRecordCountに従ってレコードを制限します。
  • 価格設定が入力から出力にどのように変化するのかわかりません。
  • EntryTypeごとにRecordCountを設定している場所がわからないため、別のCTEに追加しました。
于 2012-11-07T16:08:04.607 に答える
2
;WITH e (ID, EntryType, row, dt, Price, [Len])
AS
 (
  SELECT ID, EntryType, CASE EntryType WHEN 4 THEN 1
                                       WHEN 5 THEN 2
                                       WHEN 6 THEN 3
                                       WHEN 7 THEN 9 END AS row,
         dt, Price, 0 AS [Len] 
  FROM dbo.your_table
), x (ID, EntryType, row, dt, Price, [Len]) AS
 (
  SELECT ID, EntryType, row, dt, Price, 1
  FROM e
  UNION ALL
  SELECT e.ID, e.EntryType, e.row, e.dt, e.Price, x.[Len] + 1
  FROM e , x
  WHERE e.ID = x.ID AND e.row > x.[Len]
  )
SELECT EntryType, DATEADD(mm, ROW_NUMBER() OVER(ORDER BY EntryType)-1, dt) AS dt, Price
FROM x
ORDER BY EntryType

価格を受け取る基準が理解できない唯一のことは?

SQL Fiddleのデモ

于 2012-11-07T16:22:59.110 に答える
1

EntryType と # of row の間のロジックがわからないため、CTE で実行できるかどうかはわかりません。

質問については、必要な行数で一時テーブルを作成する方が簡単だと思います

DECLARE @Entry TABLE(EntryType INT, seq INT) 
INSERT INTO @Entry (EntryType , seq) VALUES
    (4,1)
    ,(5,1)
    ,(5,2)
    ,(6,1)
    ...
    ,(7,1)
    ..
    ,(7,9)

その後、単純なクエリでも同じ結果が得られます

SELECT  t.EntryType , DATEADD(MONTH,e.seq,  t.dt) as dt,t.Price 
FROM    YourTable t
INNER JOIN @Entry e 
    ON  t.EntryType = e.EntryType
于 2012-11-07T15:47:06.550 に答える