
visual web developer で貸し出し表を作成しています。
sqlサーバーの予定テーブルに下記のようなデータが入っています。
ID 貸し出し日 返却予定日 貸し出した物
1 2010/03/31 2010/04/03 本
2 2010/04/02 2010/04/02 DVD
3 2010/04/02 2010/04/03 CD
上記のデータで4月に貸し出しを行っている毎日の状況を抽出するにはどのようなsql文を書けばよろしいでしょうか。
下記のような結果を期待しています。
日付 ID 貸出日 返却予定日 貸し出した物
2010/04/01 1 2010/03/31 2010/04/03 本
2010/04/02 1 2010/03/31 2010/04/03 本
2010/04/02 2 2010/04/02 2010/04/02 DVD
2010/04/03 1 2010/03/31 2010/04/03 本
2010/04/03 3 2010/04/02 2010/04/03 CD
2010/04/04
2010/04/05
2010/04/06
2010/04/07
.....
2010/04/30
予定テーブルに対して「貸出日が2010/04/30以下」 or 「返却予定日が2010/04/01以上」のwhere条件で
4月の予定を抽出する事は出来ますが、複数貸し出しがある日を複数行で返し、無い日についてもNULLを返すやり方が思いつきません。
どのようなsql文を書けばよろしいでしょうか。
宜しくお願いいたします。
No.2ベストアンサー
- 回答日時:
データ量にもよるとは思いますが、、、
・貸し出し表テーブルの件数が膨大ではない
・集計は年月で絞っての日毎リスト
程度であれば、一時テーブルでもよいと思います。
一時テーブルの利点としては、カレンダテーブルのような物が必要ないということです。
欠点は、内部のループでカレンダを自力で作成するため、集計スパンが広いと、DBに負荷がかかります。
カレンダテーブルの利点としては、集計の範囲が広くてもループ処理を必要なく、集計が行えます。
欠点は、カレンダがマスタとなるので、メンテナンスを求められます。
どちらがよいかは、システムの業務フローや状態から判断するものだと思うので、ご自身でお考えください。
ストアドサンプルを載せます。
見やすくするために、[全角スペース]を利用しています。
[全角スペース]を[半角スペース2個に置換]してお使いください。
---------------------------------------
↓プロシージャ呼出はこれ(2010年04月)
EXEC PRC_月別貸出リスト '201004'
---------------------------------------
↓プロシージャ(初回はクリエイト)
CREATE PROCEDURE PRC_月別貸出リスト
--ALTER PROCEDURE PRC_月別貸出リスト
(
@s年月 AS VARCHAR(6)
)
AS
BEGIN
-- 結果返却用の一時テーブル定義
CREATE TABLE #TMP
(
日付 DATETIME,
ID INT,
貸出日 DATETIME,
返却予定日 DATETIME,
貸し出した物 VARCHAR(50)
);
DECLARE @d対象日 DATETIME;
DECLARE @i日 INT;
-- 引数年月の初日を設定
SET @d対象日 = @s年月 + '01';
-- 一回目のループを通すために、0日とする
SET @i日 = 0;
-- 翌月までループする
WHILE @i日 < DAY(@d対象日)
BEGIN
-- 抽出結果を一時テーブルに格納していく
INSERT INTO #TMP
SELECT
@d対象日,
T.ID,
T.貸し出し日,
T.返却予定日,
T.貸し出した物
FROM
貸し出し表 T
WHERE
@d対象日 BETWEEN T.貸し出し日 AND T.返却予定日;
-- 処理を行った日付を記憶
SET @i日 = DAY(@d対象日);
-- 次のループのために、対象日をインクリメント
SET @d対象日 = DATEADD(DAY, 1, @d対象日);
END;
-- 抽出結果のアウトプット
SELECT * FROM #TMP
ORDER BY 日付, ID
END
ご回答ありがとうございました。
一時テーブルの作成もストアドプロシージャも敷居が高いなっというイメージがあってなんとなく通り過ぎていた部分でした。
仰る通りで、メンテナンスやレスポンスを考えて一時テーブルやカレンダーテーブルの選択を考えたいと思います。ありがとうございました。
No.3
- 回答日時:
#2です。
失礼しました。
#1さんのって、カレンダのマスタを利用しているタイプだと勘違いしていました。
「CROSS APPLY hoge.nodes」
これよいですね。
勉強になりました。
m(_ _)m
No.1
- 回答日時:
SQLでは本質的に1件しかないものを2件以上にすることも、0件のものを1件にすることもできません。
従って、このようなニーズがある場合は、
a.2010/04/01から2010/04/30までの日付が入った「日付テーブル」なるものを別途用意しておく
b.同様のものを処理の先頭でワークテーブルやテーブル変数として生成し、それを使う
(当然1クエリにはなりませんので、ストアドプロシージャやテーブル変数として実装するのが普通)
などの対応が一般的です。
私もとりあえずはaの方法をお勧めします。その場合は「日付」というテーブルを用意しておいて、
以下のクエリとなります。
SELECT
d.日付,
t.貸し出し日,
t.返却予定日,
t.貸し出した物
FROM 日付 d
LEFT OUTER JOIN 貸し出し表 t ON d.日付 BETWEEN t.貸し出し日 AND t.返却予定日
WHERE d.日付 BETWEEN '2010/04/01' AND '2010/04/30'
ORDER BY d.日付,t.ID
どうしても日付テーブルを別途作れないし、1クエリで実行したいという状況であれば、
SQL Server 2005以降であれば、以下の方法が可能です。
ただし、この中身を理解するのは、難しいかもしれません(XQueryを使用しているため)。
SELECT
d.日付,
t.ID,
t.貸し出し日,
t.返却予定日,
t.貸し出した物
FROM
(SELECT
DATEADD(d,x.c.value('.','int'),DATEADD(d,-1,'2010/04/01')) 日付
FROM
(SELECT
CONVERT(xml,'<D>'+REPLACE('1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31',
',','</D><D>')+'</D>') 日付XML
) a
CROSS APPLY 日付XML.nodes('/D') AS x(c)
) d
LEFT OUTER JOIN 貸し出し表 t ON d.日付 BETWEEN t.貸し出し日 AND t.返却予定日
WHERE d.日付 BETWEEN '2010/04/01' AND '2010/04/30'
ORDER BY d.日付,t.ID
回答ありがとうございました。
そうですよね。やはり日付テーブルを用意してという事になりますよね。
ご提案いただいたaの方法をベースに考えてみます。
実はaの方法の場合にユーザー側で見たい月を選択して表示する方法がよくわからず質問にいたりました。
XQueryは今回初めて知りました。よく調べてみます。
難易度高そうですね。ありがとうございました!
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- Oracle sqlで質問です。 Aテーブルの情報をBテーブルに更新かけたいです。 やりたいことは、Bテーブルの受 1 2023/05/17 11:17
- Access(アクセス) アクセス where句を使用して複数条件抽出をするには 2 2022/08/29 13:24
- Oracle 質問です。 下記のテーブルとデータがあり、 取得想定結果のように出力したいです。 下記のsqlだと0 2 2023/05/23 19:10
- PostgreSQL PostgreSQL レコードからアイテム種類数を取得したい 2 2022/11/23 22:31
- 金銭トラブル・債権回収 支払督促の予告はしてもいいのか? 知り合いが1年前に貸した5万5千円を返してくれないので支払督促をし 5 2022/06/27 19:32
- その他(データベース) 更新クエリをリンクデータベーステーブルに実行し実行時エラー3362固有インデックスに重複する値が含ま 1 2022/09/21 11:44
- その他(データベース) c言語の問題です。これを踏まえてコーディングしたいのでおしえていただきたいです。 3 2023/08/03 09:27
- Excel(エクセル) エクセルの複数条件作成方法について 2 2023/01/23 21:38
- Access(アクセス) accessの日付フィールドから前年度だけを取り出したい 3 2022/04/13 23:13
- 確定申告 【確定申告】前年末未償却残高とは? 昨年令和4年分の確定申告の収支内訳書(不動産所得)について教えて 5 2023/02/12 15:44
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
日付型のフィールドに空白を入...
-
SQL文で パラメータが少なすぎ...
-
Excleピボットでデータのない部...
-
【vba】日付の形式が勝手に変わ...
-
エクセル-過去6カ月分の合計を...
-
ACCESSのレポートで次の行と比...
-
アクセスで日付を入力すると曜...
-
Excel→Accessへの日付データの...
-
ACCESSにてフィールド間の平均...
-
アクセス:既定値に土日含まず...
-
Accessで日付の比較がうまくい...
-
SQLサーバにある日付型のデータ...
-
accessのレポート
-
accessの時間更新方法(フォーム)
-
今週分だけ表示させたい
-
BCPでCSV内の文字列をテーブル...
-
access2003 あいまい検索について
-
SQL 前日分と相違があればアラ...
-
Accessの日付時刻型から日付、...
-
Accessで日付/時刻を日付型に変...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
日付型のフィールドに空白を入...
-
SQL文で パラメータが少なすぎ...
-
Excleピボットでデータのない部...
-
VBA 別シートの同じ日付の欄に...
-
アクセスで日付を入力すると曜...
-
アクセス:既定値に土日含まず...
-
Excel→Accessへの日付データの...
-
Accessの日付時刻型から日付、...
-
BCPでCSV内の文字列をテーブル...
-
エクセル-過去6カ月分の合計を...
-
Access クエリで、レコードの無...
-
前のレコードの合計に現レコー...
-
ACCESSの空白をカウントする
-
指定日付を起点にして最新日付...
-
Accessのデータ型の日付/時刻型...
-
【vba】日付の形式が勝手に変わ...
-
ビュー定義をプログラムで動的...
-
アクセスで月単位の抽出
-
【エクセル】指定した日付に一...
-
Accessで日付の比較がうまくい...
おすすめ情報