3

「予定表」と「サービス表」を持つデータベースがあります。各 appt にはサービスがあり、各サービスには価格があります。私が望むのは、常に 12 行 (各月に 1 行) を返し、(サービス ID に基づいて) 月の appts の合計を含む 1 つのクエリです。これまでのところ、私は持っています:

select sum(service_price) as monthly_total, 
       year(appt_date_time) as year, 
       monthname(appt_date_time) as month 
from appt_tbl 
     join services_tbl on appt_tbl.service_id = services_tbl.service_id 
group by month(appt_date_time), 
         year(appt_date_time) 
order by month(appt_date_time) asc;

現在、これは次のようなものを返します。

+---------------+------+-------+
| monthly_total | year | month |
+---------------+------+-------+
|        120.00 | 2012 | July  |
+---------------+------+-------+

問題は、月にアプリがない場合、クエリでその月が返されないことです。その月に記録を残したいのですが、「monthly_total」をゼロにするだけです。

以下は、クエリに返してもらいたいものです。

+---------------+------+-------+
| monthly_total | year | month |
+---------------+------+-------+
|          0.00 | 2012 | Jan   |
+---------------+------+-------+
|          0.00 | 2012 | Feb   |
+---------------+------+-------+
|          0.00 | 2012 | March |
+---------------+------+-------+
|          0.00 | 2012 | April |
+---------------+------+-------+
|          0.00 | 2012 | May   |
+---------------+------+-------+
|          0.00 | 2012 | June  |
+---------------+------+-------+
|        120.00 | 2012 | July  |
+---------------+------+-------+
|          0.00 | 2012 | August|
+---------------+------+-------+
|          0.00 | 2012 | Sept  |
+---------------+------+-------+
|          0.00 | 2012 | Oct   |
+---------------+------+-------+
|          0.00 | 2012 | Nov   |
+---------------+------+-------+
|          0.00 | 2012 | Dec   |
+---------------+------+-------+

何か案は?

4

2 に答える 2

3

LEFT JOIN月名のテーブルへのクエリの結果だけです。次に、結果に存在する名前が一致を返し、結果にNULLない月について a が返されます。COALESCEor NVLorCASEコンストラクトは、好きなものを使用して、それをNULLストレートに変換できます0

月の実際のテーブルを作成する必要はありません。インライン ビュー (すべての月のデータを生成する単純なクエリ) を使用して取得できます。

select     months.month, coalesce(appts.monthly_total, 0) monthly_total
from       (
                      select 'January' as month
           union all  select 'February' 
           union all  select 'March'

           ...etc...

           union all  select 'December'
           ) months
left join  (
            select     sum(service_price)        as monthly_total, 
                       monthname(appt_date_time) as month 
            from       appt_tbl 
            inner join services_tbl 
            on         appt_tbl.service_id = services_tbl.service_id
            where      appt_date_time between '2012-01-01 00:00:00'
                                          and '2012-12-31 23:59:59'         
            group by   month(appt_date_time)
           ) appts
on         months.month = appts.month 

特定の年のすべてを返す場合は、WHERE 条件を見てください。appt_date_time は日時またはタイムスタンプであると想定しています。YEAR(appt_date_time) = 2012 と書きたくないのは、その列でインデックスを使用する可能性がなくなるためです (列がインデックスの最初の列として表示されると想定しています)。BETWEEN...AND を使用し、リテラルの日時と比較することで、要件を満たす非常に効率的なクエリを作成できます。

GROUP BYまた、mysql を使用している場合は、month(appt_date_time)結果が月ごとに昇順でソートされることも保証されます。したがって、別のORDER BY. UNION クエリの「レッグ」の順序も mysql によって保持されます。

于 2012-07-17T06:04:01.113 に答える
1

これを試してください、それはあなたのために働くでしょう. あなたがする必要があるのは、より良いアプローチのためにルックアップテーブルを作成することだけです.

CREATE TABLE MONTHS(MON CHAR(3))
INSERT INTO MONTHS 
SELECT 'Jan' UNION ALL
SELECT 'Feb' UNION ALL
SELECT 'Mar' UNION ALL
SELECT 'Apr' UNION ALL
SELECT 'May' UNION ALL
SELECT 'Jun' UNION ALL
SELECT 'Jul' UNION ALL
SELECT 'Aug' UNION ALL
SELECT 'Sep' UNION ALL
SELECT 'Oct' UNION ALL
SELECT 'Nov' UNION ALL
SELECT 'Dec'

CREATE  TABLE Appointments(App int, Year int, Month CHAR(3))
INSERT INTO Appointments 
SELECT 120,2012,'Jul' UNION ALL 
SELECT 120,2013,'Apr'

SELECT sum(isnull(App,0)) monthly_total, b.Mon , b.Year FROM Appointments a
RIGHT JOIN (SELECT DISTINCT Year,Mon FROM Appointments CROSS JOIN MONTHS) b 
ON a.Month=b.MON AND a.Year=b.Year
GROUP BY b.Mon,b.Year
于 2012-07-17T06:25:50.680 に答える