SQL Server2008に次のようなテーブルがあるとします。
id | name | qty
-------------------
1 | john | 1
2 | bill | 3
3 | mary | 2
4 | jill | 5
このテーブルをクエリして、最大で2の数量のバッチごとに1行を返したいので、クエリの結果は次のようになります。
id | name | qty
-------------------
1 | john | 1
2 | bill | 2
2 | bill | 1
3 | mary | 2
4 | jill | 2
4 | jill | 2
4 | jill | 1
これはカーソルを使わずにきちんと行うことができますか? unpivotを使用してこれは可能ですか?
ちなみに、qty
列の最大値は10です。
数字の表があれば簡単です。また、qty
は10
を超えることはできないため、必要なのは非常に小さい数値のテーブルだけです。
CREATE TABLE numbers
( i int NOT NULL PRIMARY KEY ) ;
INSERT INTO numbers (i)
VALUES (1), (3), (5), (7), (9) ;
結果に必要な行数はqty
の半分(または約半分)であるため、奇数のみが必要です。
クエリ:
SELECT
t.id, t.name,
qty = CASE WHEN n.i = 1 AND t.qty % 2 > 0 THEN t.qty % 2 ELSE 2 END
FROM
tableX AS t
JOIN
numbers AS n
ON
n.i <= t.qty ;
もちろん、補助テーブルなしでそれを行うこともできます。
SELECT
t.id, t.name,
qty = CASE WHEN n.i = 1 AND t.qty % 2 > 0 THEN t.qty % 2 ELSE 2 END
FROM
tableX AS t
JOIN
(VALUES (1), (3), (5), (7), (9)) AS n (i)
ON
n.i <= t.qty ;
dbfiddle.uk でテスト済み。
関数を使用して、次のような元のテーブルに適用することもできます。
CREATE FUNCTION NumbersTable (
@fromNumber int,
@toNumber int,
@originalQty int
) RETURNS TABLE
RETURN (
WITH CTE_NumbersTable AS (
SELECT case when @originalQty = @fromNumber then 1 else 2 end AS i,case when @originalQty = @fromNumber then 1 else 2 end AS i2
UNION ALL
SELECT case when i2 +2 < @toNumber then 2 else 1 end as i , i2 = i2 + case when i2 +2 <= @toNumber then 2 else 1 end
FROM CTE_NumbersTable
WHERE
i2 < @toNumber
)
SELECT i FROM CTE_NumbersTable
)
そしてそれをテーブルで使用します:
select id,name,Quantity2.i as qty from TestNames
cross apply dbo.NumbersTable(1,qty,qty) as Quantity2