3

作成しようとしている SQL クエリについて質問があります。

データベースからデータを照会する必要があります。データベースには、特に次の 3 つのフィールドがあります。

Account_ID #, Date_Created, Time_Created

1 時間あたりにいくつの口座が開設されたかを示すクエリを作成する必要があります。

上記のクエリを作成しましたが、作成されたアカウントが 0 である場合があるため、これらの「時間」は結果に入力されません。

例えば:

ボリューム日付_ _
435 12-Aug-12 03
213 12-Aug-12 04
125 12-Aug-12 06

上記の例に見られるように、5 時間目には口座が開かれませんでした。

結果が時間に入力され、この時間に開かれたアカウントが 0 件表示される方法はありますか? 結果を次のように表示する方法の例:

ボリュームDate _Hour
435 12-Aug-12 03
213 12-Aug-12 04
0 12-Aug-12 05
125 12-Aug-12 06

ありがとう!

更新:これは私がこれまでに持っているものです

SELECT count(*) as num_apps, to_date(created_ts,'DD-Mon-RR') as app_date, to_char(created_ts,'HH24') as app_hour 
FROM accounts 
WHERE To_Date(created_ts,'DD-Mon-RR') >= To_Date('16-Aug-12','DD-Mon-RR') 
GROUP BY To_Date(created_ts,'DD-Mon-RR'), To_Char(created_ts,'HH24') 
ORDER BY app_date, app_hour
4

5 に答える 5

2

必要な結果を得るには、テーブルを作成する (またはクエリを使用して「一時」テーブルを生成する) 必要があります。次に、左結合を計算クエリに使用して、ボリュームが 0 の場合でも、1 時間ごとに行を取得します。

たとえば、app_date フィールドと app_hour フィールドを含むテーブルがあるとします。また、このテーブルには、レポートしたい日/時間ごとの行があると仮定します。

クエリは次のようになります。

SELECT NVL(c.num_apps,0) as num_apps, t.app_date, t.app_hour
    FROM time_table t
    LEFT OUTER JOIN 
    (
    SELECT count(*) as num_apps, to_date(created_ts,'DD-Mon-RR') as app_date, to_char(created_ts,'HH24') as app_hour 
    FROM accounts 
    WHERE To_Date(created_ts,'DD-Mon-RR') >= To_Date('16-Aug-12','DD-Mon-RR') 
    GROUP BY To_Date(created_ts,'DD-Mon-RR'), To_Char(created_ts,'HH24') 
    ORDER BY app_date, app_hour
    ) c ON (t.app_date = c.app_date AND t.app_hour = c.app_hour)
于 2012-10-02T19:26:23.867 に答える
1

最善の解決策は、派手な一時テーブルを作成するのではなく、次の構成を使用することだと思います。

select level
FROM Dual
CONNECT BY level <= 10
ORDER BY level;

これにより、(10行で)次のようになります: 1 2 3 4 5 6 7 8 9 10

時間間隔の場合は、少し変更します。

select 0 as num_apps, (To_Date('16-09-12','DD-MM-RR') + level / 24) as created_ts
FROM dual
CONNECT BY level <= (sysdate - To_Date('16-09-12','DD-MM-RR')) * 24 ;  

そして、あなたのためにソリューションを追加する楽しみのために(私は構文を試していないので、間違いは申し訳ありませんが、アイデアは明らかです):

 SELECT SUM(num_apps) as num_apps, to_date(created_ts,'DD-Mon-RR') as app_date, to_char(created_ts,'HH24') as app_hour 
FROM(
  SELECT count(*) as num_apps, created_ts
  FROM accounts 
  WHERE To_Date(created_ts,'DD-Mon-RR') >= To_Date('16-09-12','DD-MM-RR') 
UNION ALL
  select 0 as num_apps, (To_Date('16-09-12','DD-MM-RR') + level / 24) as created_ts
  FROM dual
  CONNECT BY level <= (sysdate - To_Date('16-09-12','DD-MM-RR')) * 24 ;  
)
GROUP BY To_Date(created_ts,'DD-Mon-RR'), To_Char(created_ts,'HH24') 
ORDER BY app_date, app_hour
;
于 2012-10-02T21:39:12.810 に答える
0

SELECTでCASEステートメントを使用して、必要な値を強制することもできます。

于 2012-10-02T19:29:09.483 に答える
0

created_tsがdatetimeかvarcharかはわかりません。日時の場合は、使用しないでくださいto_date。varchar の場合は、使用しないでくださいto_char

それがdatetimeであると仮定し、@ jakub.petrのFROM Dual CONNECT BY levelトリックを借りて、私は提案します:

SELECT count(*) as num_apps, to_char(created_ts,'DD-Mon-RR') as app_date, to_char(created_ts,'HH24') as app_hour 
FROM (select level-1 as hour FROM Dual CONNECT BY level <= 24) h 
  LEFT JOIN accounts a on h.hour = to_number(to_char(a.created_ts,'HH24'))
WHERE created_ts >= To_Date('16-Aug-12','DD-Mon-RR') 
GROUP BY trunc(created_ts), h.hour 
ORDER BY app_date, app_hour
于 2012-10-03T08:39:40.913 に答える
0

あらゆる種類の理由で、次のような「シーケンス テーブル」を使用すると便利です。

create table dbo.sequence
(
  id int not null primary key clustered ,  
)

正の値と負の値をカバーする、100 万行程度の行をロードします。

次に、このようなテーブルが与えられた場合

create table dbo.SomeTable
(
  account_id   int  not null primary key clustered ,
  date_created date not null ,
  time_created time not null ,
)

クエリは次のように単純です (SQL Server の場合):

select year_created  = years.id  ,
       month_created = months.id ,
       day_created   = days.id   ,
       hour_created  = hours.id  ,
       volume        = t.volume
from       ( select * ,
                    is_leap_year = case
                                   when id % 400 = 0 then 1
                                   when id % 100 = 0 then 0
                                   when id %   4 = 0 then 1
                                   else                   0
                                   end
             from dbo.sequence
             where id between 1980 and year(current_timestamp)
           ) years
cross join ( select *
             from dbo.sequence
             where id between 1 and 12
           ) months
left  join ( select *
             from dbo.sequence
             where id between 1 and 31
           ) days on days.id <= case months.id
                                when  2 then 28 + years.is_leap_year
                                when  4 then 30
                                when  6 then 30
                                when  9 then 30
                                when 11 then 30
                                else         31
                                end
cross join ( select *
             from dbo.sequence
             where id between 0 and 23
           ) hours
left join ( select date_created ,
                   hour_created = datepart(hour,time_created ) ,
                   volume = count(*)
            from dbo.SomeTable
            group by date_created ,
                     datepart(hour,time_created)
          ) t on datepart( year  , t.date_created ) = years.id
             and datepart( month , t.date_created ) = months.id
             and datepart( day   , t.date_created ) = days.id
             and t.hour_created                     = hours.id
order by 1,2,3,4
于 2012-10-02T19:55:26.843 に答える