2017-07-11 5 views
-2

私はこの質問の説明的なタイトルについてはわかりませんでしたので、私は最高の文章と思っていました。実際に存在するよりも多くの行をテーブルから取得しようとしています

私はこのようなテーブルがあります。

必要な出力:

1, 1, 2016, P -- <-- it is 'P' in the table 
1, 2, 2016, A 
1, 3, 2016, A 
1, 4, 2016, A 
1, 5, 2016, A 
1, 6, 2016, A 
1, 7, 2016, A 
1, 8, 2016, A 
1, 9, 2016, A 
1, 10, 2016, A 
1, 11, 2016, A 
1, 12, 2016, P -- <-- it is 'P' in the table 
1, 1, 2017, A 
1, 2, 2017, A 
1, 3, 2017, A 
1, 4, 2017, P -- <-- it is 'P' in the table 
1, 5, 2017, A 
1, 6, 2017, A 
1, 7, 2017, A 
1, 8, 2017, A 
1, 9, 2017, A 
1, 10, 2017, A 
1, 11, 2017, A 
1, 12, 2017, A 
私は1以下のような結果セットを返すために、カーソルを使用せずに、SQL文を書きたい

StudentID, Month, Year, Present 
------------------------------- 
1, 1, 2016, P 
1, 12, 2016, P 
1, 4, 2017, P 

これは、カーソルを使用せずに、1つのSQL文で可能です。

私はSQL Server 2000データベースを作成しています。

+2

SQL Server 2000は、そうでない場合、私はCTEを経由して目的の間隔を構築すると言うし、その後に存在するテーブルを結合する左のだろう...かなりケースを制限しますそれ。それはSQL Server 2000でなければならないのですか? – Adwaenyth

+0

古いバージョンのSQL Serverを使用している人はどれだけ多いのでしょうか。私は昨年、SQL Serverのユーザーグループに所属していて、そのスピーカーは、どのバージョンのユーザーが使用していたかを尋ねました。彼がリストを逆戻りしたとき、彼は実際に「私はほとんど尋ねることを恐れている... SQL Server 6.5の誰でも」と彼はまだ手を上げている。 –

+0

ええ、最近、私たちは最近SQL Server 2016にアップグレードしました。戻ってくることは想像できませんでした。 – Adwaenyth

答えて

-2

私はあなたが必要とするすべての年月のテーブル(集計)を作成することでそれを行うことができると思います。 サンプルデータ:

CREATE TABLE TD1 (YYEAR SMALLINT, MMONTH SmALLINT); 
INSERT INTO TD1 VALUES (2016,1); 
INSERT INTO TD1 VALUES (2016,2); 
INSERT INTO TD1 VALUES (2016,3); 
INSERT INTO TD1 VALUES (2016,4); 
INSERT INTO TD1 VALUES (2016,5); 
INSERT INTO TD1 VALUES (2016,6); 
INSERT INTO TD1 VALUES (2016,7); 
INSERT INTO TD1 VALUES (2016,8); 
INSERT INTO TD1 VALUES (2016,9); 
INSERT INTO TD1 VALUES (2016,10); 
INSERT INTO TD1 VALUES (2016,11); 
INSERT INTO TD1 VALUES (2016,12); 
INSERT INTO TD1 VALUES (2017,1); 
INSERT INTO TD1 VALUES (2017,2); 
INSERT INTO TD1 VALUES (2017,3); 
INSERT INTO TD1 VALUES (2017,4); 
INSERT INTO TD1 VALUES (2017,5); 
INSERT INTO TD1 VALUES (2017,6); 
INSERT INTO TD1 VALUES (2017,7); 
INSERT INTO TD1 VALUES (2017,8); 
INSERT INTO TD1 VALUES (2017,9); 
INSERT INTO TD1 VALUES (2017,10); 
INSERT INTO TD1 VALUES (2017,11); 
INSERT INTO TD1 VALUES (2017,12); 

CREATE TABLE TS1 (StudentId INT, MMONTH SMALLINT, YYEAR SMALLINT, PRESENT CHAR(1)) 
INSERT INTO TS1 VALUES (1,1,2016,'P'); 
INSERT INTO TS1 VALUES (1,12,2016,'P'); 
INSERT INTO TS1 VALUES (1,4,2017,'P'); 
INSERT INTO TS1 VALUES (2,3,2017,'P'); 

問合せ:

SELECT A.STUDENTID, TD1.MMONTH, TD1.YYEAR, COALESCE(TS1.PRESENT, 'A') AS PRESENT 
FROM TD1 
CROSS JOIN (SELECT DISTINCT STUDENTID FROM TS1) A 
LEFT JOIN TS1 On TD1.MMONTH=TS1.MMONTH AND TD1.YYEAR=TS1.YYEAR AND A.STUDENTID = TS1.STUDENTID 
ORDER BY A.STUDENTID, TD1.YYEAR, TD1.MMONTH; 

出力:

+-----------+--------+-------+---------+ 
| STUDENTID | MMONTH | YYEAR | PRESENT | 
+-----------+--------+-------+---------+ 
|   1 |  1 | 2016 | P  | 
|   1 |  2 | 2016 | A  | 
|   1 |  3 | 2016 | A  | 
|   1 |  4 | 2016 | A  | 
|   1 |  5 | 2016 | A  | 
|   1 |  6 | 2016 | A  | 
|   1 |  7 | 2016 | A  | 
|   1 |  8 | 2016 | A  | 
|   1 |  9 | 2016 | A  | 
|   1 |  10 | 2016 | A  | 
|   1 |  11 | 2016 | A  | 
|   1 |  12 | 2016 | P  | 
|   1 |  1 | 2017 | A  | 
|   1 |  2 | 2017 | A  | 
|   1 |  3 | 2017 | A  | 
|   1 |  4 | 2017 | P  | 
|   1 |  5 | 2017 | A  | 
|   1 |  6 | 2017 | A  | 
|   1 |  7 | 2017 | A  | 
|   1 |  8 | 2017 | A  | 
|   1 |  9 | 2017 | A  | 
|   1 |  10 | 2017 | A  | 
|   1 |  11 | 2017 | A  | 
|   1 |  12 | 2017 | A  | 
|   2 |  1 | 2016 | A  | 
|   2 |  2 | 2016 | A  | 
|   2 |  3 | 2016 | A  | 
|   2 |  4 | 2016 | A  | 
|   2 |  5 | 2016 | A  | 
|   2 |  6 | 2016 | A  | 
|   2 |  7 | 2016 | A  | 
|   2 |  8 | 2016 | A  | 
|   2 |  9 | 2016 | A  | 
|   2 |  10 | 2016 | A  | 
|   2 |  11 | 2016 | A  | 
|   2 |  12 | 2016 | A  | 
|   2 |  1 | 2017 | A  | 
|   2 |  2 | 2017 | A  | 
|   2 |  3 | 2017 | P  | 
|   2 |  4 | 2017 | A  | 
|   2 |  5 | 2017 | A  | 
|   2 |  6 | 2017 | A  | 
|   2 |  7 | 2017 | A  | 
|   2 |  8 | 2017 | A  | 
|   2 |  9 | 2017 | A  | 
|   2 |  10 | 2017 | A  | 
|   2 |  11 | 2017 | A  | 
|   2 |  12 | 2017 | A  | 
+-----------+--------+-------+---------+ 
0

あなたが欠落しているエンティティのためのテーブルを作成する必要があります。たとえば、すべての年のすべての月と年と月のエンティティ:

CREATE TABLE Month_Table (
    Month_ID int NOT NULL, 
    PRIMARY KEY (Month_ID) 
); 
CREATE TABLE Year_Table (
    Year_ID int NOT NULL, 
    PRIMARY KEY (Year_ID) 
); 

は、次に使用LEFT OUTERはに参加し2016年から2017年

に番号を1から12までの数字でMonth_Tableを入力し、Year_Table不足している値をそれらのテーブルによって提供されるもので埋める。

SELECT T.StudentID, 
    COALESCE(T.Month, Month_Table.Month_ID) Month, 
    COALESCE(T.Year, Year_Table.Year_ID) Year, 
    COALESCE(T.Present, 'A') Present 
FROM YOUR_TABLE T 
LEFT OUTER JOIN Month_Table ON Month_Table.Month_ID = YOUR_TABLE 
LEFT OUTER JOIN Year_Table ON Year_Table.Year_ID = YOUR_TABLE.Year; 
2

あなたは集計テーブルを使用して12までの数字1を生成することができます:あなたのテーブルは、それらが含まれていない、とあなたのテーブルにデータが含まれていないとき、「」場合は補助テーブルからの値を使用するようにCOALESCEを使用しますその後、クロスは、以下のように適用されます:ここで

;with cte1 as 
(select * from (values (1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) a(n)) --number generation 
,Cte_numbers as (select num = Row_number() over (order by (SELECT NULL)) from cte1 c1, cte1 c2, cte1 c3) 
Select s.StudentId, n.num as [Month], s.[Year], Coalesce(s1.Present,'A') as Present from (
    Select distinct StudentId, [YEAR] from #student) s 
    cross apply (Select top (12) num from Cte_numbers) n 
left join #student s1 
    on s.StudentId = s1.StudentId 
    and s.[Year] = s1.[Year] 
    and n.num = s1.[Month] 
    order by s.StudentId, s.[Year] 
+1

残念ながらSQL Sever 2000の共通テーブル式はありません。 –

+0

次に、サブクエリの場合と同じように、サブクエリ –

+0

とSQL 2000の「CROSS APPLY」のどちらにも書くことができます。 –

0

は、ちょうどこれはSQL Serverの2005年以降であるいかに簡単かを示すために、SQL Serverで動作するはずその後、例など二つの例、CTEを使用するもの、再帰、です

他の回答と同様に、これは基本的に数字重い持ち上げをするためにテーブルをタリー。ここに番号を生成する方法についての良い記事があります:https://sqlperformance.com/2013/01/t-sql-queries/generate-a-set-1

DECLARE @MyData TABLE (StudentId INT, [Month] INT, [Year] INT, Present CHAR(1)); 
INSERT INTO @MyData SELECT 1, 1, 2016, 'P'; 
INSERT INTO @MyData SELECT 1, 12, 2016, 'P'; 
INSERT INTO @MyData SELECT 1, 4, 2017, 'P'; 

--Recursive CTE to load numbers table dynamically 
WITH Numbers AS (
    SELECT 1 AS [Month], 2016 AS [Year] 
    UNION ALL 
    SELECT CASE WHEN [Month] = 12 THEN 1 ELSE [Month] + 1 END, CASE WHEN [Month] = 12 THEN [Year] + 1 ELSE [Year] END 
    FROM Numbers 
    WHERE [Year] < 2017 OR [Month] < 12), 
Students AS (
    SELECT DISTINCT StudentId FROM @MyData) 
SELECT 
    s.StudentId, 
    n.[Year], 
    n.[Month], 
    ISNULL(m.Present, 'A') AS Present 
FROM 
    Students s 
    CROSS JOIN Numbers n 
    LEFT JOIN @MyData m ON m.StudentId = s.StudentId AND m.[Year] = n.[Year] AND m.[Month] = n.[Month] 
OPTION (MAXRECURSION 0); 

--SQL Server 2000 doesn't have CTEs so we have to use a different method 
DECLARE @Numbers TABLE ([Year] INT, [Month] INT); 
DECLARE @Year INT = 2016; 
WHILE @Year < 2018 
BEGIN 
    DECLARE @Month INT = 1; 
    WHILE @Month < 13 
    BEGIN 
     INSERT INTO @Numbers SELECT @Year, @Month; 
     SELECT @Month = @Month + 1; 
    END; 
    SELECT @Year = @Year + 1; 
END; 

--SQL Server 2000 query 
SELECT 
    s.StudentId, 
    n.[Year], 
    n.[Month], 
    ISNULL(m.Present, 'A') AS Present 
FROM 
    (SELECT DISTINCT StudentId FROM @MyData) s 
    CROSS JOIN @Numbers n 
    LEFT JOIN @MyData m ON m.StudentId = s.StudentId AND m.[Year] = n.[Year] AND m.[Month] = n.[Month]; 
関連する問題