Quantity of data per month - sql

I have to calculate the number of cars a day - of every month
I tried to do this using the Datediff formula
But I can't add the segmentation of each month either.
Attached script table:
create table TABLE_A(Code FLOAT,DateIn datetime,dateOut datetime,Garage varchar(30)
)
insert into Table_A (Code,DateIn,dateOut,Garage) values
('1','2018-06-07 00:00:00.000','2018-12-19 00:00:00.000','X'),
('2','2018-05-30 00:00:00.000','2018-12-19 00:00:00.000','Y'),
('3','2018-08-08 00:00:00.000','2018-11-18 00:00:00.000','Z'),
('4','2018-12-30 00:00:00.000','2018-12-30 00:00:00.000','Y'),
('5','2018-09-16 00:00:00.000','2018-10-19 00:00:00.000','Y'),
('6','2018-05-08 00:00:00.000','2018-08-28 00:00:00.000','Z'),
('7','2018-01-29 00:00:00.000','2018-07-31 00:00:00.000','Z'),
('8','2018-05-24 00:00:00.000','2018-09-10 00:00:00.000','X'),
('9','2018-05-02 00:00:00.000','2018-06-30 00:00:00.000','Y'),
('10','2018-07-05 00:00:00.000','2018-12-09 00:00:00.00','Z')
And this is the structure of the query result that should be:(Columns:Year,month,Garage-Number of vehicles per day by month)
Year month X Y Z
2018 1
2018 2
2018 3
2018 4
2018 5
2018 6
2018 7
2018 8
2018 9
2018 10
2018 11
2018 12
Thanks for the help.

You can first generate the list of months and year and then can left join your table to that -
WITH MONTHS AS (SELECT 1 MNTHS
UNION ALL
SELECT 2
UNION ALL
SELECT 3
UNION ALL
SELECT 4
UNION ALL
SELECT 5
UNION ALL
SELECT 6
UNION ALL
SELECT 7
UNION ALL
SELECT 8
UNION ALL
SELECT 9
UNION ALL
SELECT 10
UNION ALL
SELECT 11
UNION ALL
SELECT 12),
YEAR AS (SELECT 2018 YEAR)
SELECT YEAR,
MNTHS,
SUM(CASE WHEN Garage = 'X' THEN 1 ELSE 0 END) AS X,
SUM(CASE WHEN Garage = 'Y' THEN 1 ELSE 0 END) AS Y,
SUM(CASE WHEN Garage = 'Z' THEN 1 ELSE 0 END) AS Z
FROM (SELECT * FROM MONTHS M CROSS JOIN YEAR Y) YEARS
LEFT JOIN TABLE_A T ON YEARS.MNTHS = MONTH(T.DateIn)
AND YEARS.YEAR = YEAR(T.DateIn)
GROUP BY YEAR(DateIn),
MONTH(DateIn),
MNTHS,
YEAR
ORDER BY YEAR,
MNTHS
Here is the fiddle

The following query should do what you want, the Recursive CTE part is used to figure out dates between each DayIn and DayOut. Once we have the complete list of dates, in the main query we do a conditional aggregation to find out the DISTINCT number of cars in the garage each month,
CREATE TABLE TABLE_A (Code FLOAT,DateIn DATETIME,dateOut DATETIME,Garage VARCHAR(30))
INSERT INTO Table_A (Code,DateIn,dateOut,Garage) VALUES
('1','2018-06-07 00:00:00.000','2018-12-19 00:00:00.000','X'),
('2','2018-05-30 00:00:00.000','2018-12-19 00:00:00.000','Y'),
('3','2018-08-08 00:00:00.000','2018-11-18 00:00:00.000','Z'),
('4','2018-12-30 00:00:00.000','2018-12-30 00:00:00.000','Y'),
('5','2018-09-16 00:00:00.000','2018-10-19 00:00:00.000','Y'),
('6','2018-05-08 00:00:00.000','2018-08-28 00:00:00.000','Z'),
('7','2018-01-29 00:00:00.000','2018-07-31 00:00:00.000','Z'),
('8','2018-05-24 00:00:00.000','2018-09-10 00:00:00.000','X'),
('9','2018-05-02 00:00:00.000','2018-06-30 00:00:00.000','Y'),
('10','2018-07-05 00:00:00.000','2018-12-09 00:00:00.00','Z')
/** Main Query Starts Here **/
;WITH CTE ([Code],[DateIn],[DateOut],[Garage]) AS (
SELECT [Code], [DateIn], [DateOut], [Garage]
FROM TABLE_A WHERE [DateIn] <= [DateOut]
UNION ALL
SELECT [Code], DATEADD(DAY, 1, [DateIn]), [DateOut], [Garage]
FROM CTE
WHERE [DateIn] < [DateOut])
SELECT
YEAR([DateIn]) AS [Year]
,MONTH([DateIn]) AS [Month]
,COUNT( DISTINCT CASE WHEN [Garage] = 'X' THEN T.t1 ELSE NULL END) AS X
,COUNT( DISTINCT CASE WHEN [Garage] = 'Y' THEN T.t1 ELSE NULL END) AS Y
,COUNT( DISTINCT CASE WHEN [Garage] = 'Z' THEN T.t1 ELSE NULL END) AS Z
FROM CTE
CROSS APPLY (VALUES (CONVERT(VARCHAR(4),YEAR([DateIn])) + CONVERT(VARCHAR(2),MONTH([DateIn])) + CONVERT(VARCHAR(20),[Code]))) AS T(t1)
GROUP BY YEAR([DateIn]), MONTH([DateIn])
ORDER BY [Year], [Month]
OPTION (MAXRECURSION 0)
The result is as below,
Year Month X Y Z
2018 1 0 0 1
2018 2 0 0 1
2018 3 0 0 1
2018 4 0 0 1
2018 5 1 2 2
2018 6 2 2 2
2018 7 2 1 3
2018 8 2 1 3
2018 9 2 2 2
2018 10 1 2 2
2018 11 1 1 2
2018 12 1 2 1

You can generate the dates using a recursive subquery.
Then you have multiple ways to calculate the summary data. One simple method uses apply:
with dates as (
select convert(date, '2018-01-01') as dte, 1 as lev
union all
select dateadd(month, 1, dte), lev + 1
from dates
where lev < 12
)
select year(d.dte), month(d.dte), s.*
from dates d outer apply
(select sum(case when a.Garage = 'X' then 1 else 0 end) as x,
sum(case when a.Garage = 'Y' then 1 else 0 end) as y,
sum(case when a.Garage = 'Z' then 1 else 0 end) as z
from table_a a
where a.datein <= d.dte and a.dateout >= d.dte
) s;
Your question is a little vague on the exact calculation. This calculates the number of cars in each garage on the first of each month.
Here is a db<>fiddle.
EDIT:
Your revised question is more complicated, but since I started answering:
with dates as (
select convert(date, '2018-01-01') as dte, 1 as lev
union all
select dateadd(month, 1, dte), lev + 1
from dates
where lev < 12
)
select year(d.dte), month(d.dte),
sum(case when a.Garage = 'X'
then datediff(day,
(case when a.datein < d.dte then d.dte else datein end),
(case when a.dateout >= dateadd(month, 1, d.dte) then eomonth(d.dte) else dateout end)
) + 1
else 0
end) as x_cardays,
sum(case when a.Garage = 'Y'
then datediff(day,
(case when a.datein < d.dte then d.dte else datein end),
(case when a.dateout >= dateadd(month, 1, d.dte) then eomonth(d.dte) else dateout end)
) + 1
else 0
end) as y_cardays,
sum(case when a.Garage = 'Z'
then datediff(day,
(case when a.datein < d.dte then d.dte else datein end),
(case when a.dateout >= dateadd(month, 1, d.dte) then eomonth(d.dte) else dateout end)
) + 1
else 0
end) as z_cardays
from (select d.*, day(eomonth(dte)) as days_in_month
from dates d
) d left join
table_a a
on a.datein < dateadd(month, 1, d.dte) and a.dateout >= d.dte
group by d.dte
order by d.dte;
Overlaps with dates are a bit tricky, but you definitely want to do this with dates.
Note this doesn't calculate the average per day. You can divide by d.days_in_month if you want the average.
Here is a revised db<>fiddle.

This below script will only work if all your DateIn and DateOut for a particular record is in a single year like 2018.
Leap year Year is not considered but can be implemented.
WITH Month_Wise_Day AS
(
-- Listing/selecting 12 month manually here
-- With number of day for that month
SELECT 1 M, 31 ND UNION ALL
SELECT 2 M, 28 UNION ALL SELECT 3 M,31 UNION ALL SELECT 4 M,30 UNION ALL SELECT 5 M,31 UNION ALL
SELECT 6 M,30 UNION ALL SELECT 7 M,31 UNION ALL SELECT 8 M,31 UNION ALL SELECT 9 M,30 UNION ALL
SELECT 10 M,31 UNION ALL SELECT 11 M,30 UNION ALL SELECT 12 M,31
)
SELECT A.Year, A.Month,
SUM(CASE WHEN A.Garage = 'X' THEN A.No_of_days ELSE 0 END) AS X,
SUM(CASE WHEN A.Garage = 'Y' THEN A.No_of_days ELSE 0 END) AS Y,
SUM(CASE WHEN A.Garage = 'Z' THEN A.No_of_days ELSE 0 END) AS Z
FROM
(
SELECT A.*,
B.M AS Month,
YEAR(A.DateIn) AS Year,
CASE
WHEN MONTH(A.DateIn) = MONTH(A.DateOut) THEN DATEDIFF(DD,DateIn,DateOut) +1
WHEN B.M = MONTH(DateIn) THEN B.ND - DAY(DateIn)+1
WHEN B.M = MONTH(DateOut) THEN DAY(DateOut)
ELSE ND
END No_of_days
FROM TABLE_A A
INNER JOIN Month_Wise_Day B ON B.M BETWEEN MONTH(DateIn) AND MONTH (DateOut)
)A
GROUP BY A.Year, A.Month

Related

Select all days in a week, when calendarweek is given

certainly something very simple, but for an application I would like to know how, if I know the calendar week, I can display the first to the last day of the week per row.
Currently, I am only shown the day in which content is present.
I would like to have 7 days displayed (as date, not necessarily with name) whether they are empty or not.
SELECT
MIN( TO_CHAR(LP_BELEGUNG.GEN_DATUM,'DD.MM.YYYY')) AS GRD_ROW_ID
, COUNT( DISTINCT
CASE
WHEN LP_BELEGUNG.ART = 1 THEN LP_BELEGUNG.LP_BELEGUNG_ID
ELSE NULL
END ) AS ANZAHL_ART_1
, COUNT( DISTINCT
CASE
WHEN LP_BELEGUNG.ART = 2 THEN LP_BELEGUNG.LP_BELEGUNG_ID
ELSE NULL
END ) AS ANZAHL_ART_2
, COUNT( DISTINCT
CASE
WHEN LP_BELEGUNG.ART = 3 THEN LP_BELEGUNG.LP_BELEGUNG_ID
ELSE NULL
END ) AS ANZAHL_ART_3
, COUNT( DISTINCT
CASE
WHEN LP_BELEGUNG.ART = 99 THEN LP_BELEGUNG.LP_BELEGUNG_ID
ELSE NULL
END ) AS ANZAHL_ART_4
FROM
LP_BELEGUNG
WHERE
TO_CHAR(LP_BELEGUNG.GEN_DATUM, 'WW') = 37 --the calendar week
If you want one row per day, for a week number in a given year, then you can generate all the dates in that week and use an outer join to look for matching rows in your table, if there are any.
Unfortunately Oracle doesn't supply a simple way to get a date from a week number, but based on how the WW element is defined you can start from the first day of the year and add the appropriate number of days to get the start of the week:
select trunc(sysdate, 'YYYY') + (7 * 37) - 7 from dual;
TRUNC(SYSDATE,'YYYY')+(7*37)-7
10-SEP-22
... where 37 is the week number, and I've assumed you're looking at the current year (if not, use a fixed date like date '2022-01-01' instead of trunc(sysdate)).
You can then get all the days in that week with a hierarchical query:
select trunc(sysdate, 'YYYY') + (7 * 37) + level - 8
from dual
connect by level <= 7;
TRUNC(SYSDATE,'YYYY')+(7*37)+LEVEL-8
10-SEP-22
11-SEP-22
12-SEP-22
13-SEP-22
14-SEP-22
15-SEP-22
16-SEP-22
Then use those values in an inline view or CTE, and left-join to your table using a date range (to allow for non-midnight times but still allowing an index on that column to be used), grouping by the date:
with cte (dt) as (
select trunc(sysdate, 'YYYY') + (7 * 37) + level - 8
from dual
connect by level <= 7
)
SELECT
TO_CHAR(cte.dt, 'DD.MM.YYYY') AS GRD_ROW_ID
, COUNT( DISTINCT
CASE
WHEN LP_BELEGUNG.ART = 1 THEN LP_BELEGUNG.LP_BELEGUNG_ID
ELSE NULL
END ) AS ANZAHL_ART_1
, COUNT( DISTINCT
CASE
WHEN LP_BELEGUNG.ART = 2 THEN LP_BELEGUNG.LP_BELEGUNG_ID
ELSE NULL
END ) AS ANZAHL_ART_2
, COUNT( DISTINCT
CASE
WHEN LP_BELEGUNG.ART = 3 THEN LP_BELEGUNG.LP_BELEGUNG_ID
ELSE NULL
END ) AS ANZAHL_ART_3
, COUNT( DISTINCT
CASE
WHEN LP_BELEGUNG.ART = 99 THEN LP_BELEGUNG.LP_BELEGUNG_ID
ELSE NULL
END ) AS ANZAHL_ART_4
FROM
cte
LEFT JOIN
LP_BELEGUNG
ON
LP_BELEGUNG.GEN_DATUM >= cte.dt AND LP_BELEGUNG.GEN_DATUM < cte.dt + 1
GROUP BY
cte.dt
ORDER BY
cte.dt
With some sample data to mimic your original result, that gives:
GRD_ROW_ID
ANZAHL_ART_1
ANZAHL_ART_2
ANZAHL_ART_3
ANZAHL_ART_4
10.09.2022
0
0
0
0
11.09.2022
0
0
0
0
12.09.2022
0
0
0
0
13.09.2022
0
0
0
0
14.09.2022
0
0
0
0
15.09.2022
0
0
0
0
16.09.2022
1
0
0
7
fiddle
Here is a set of dates counted and divided to days of the week using to_char and pivot.
select *
from
(
select dt
,to_char(dt, 'D') as dow
from t
) t
pivot (count(dt) for dow in('1', '2', '3', '4', '5', '6', '7')) p
'1'
'2'
'3'
'4'
'5'
'6'
'7'
1
1
0
0
1
3
1
Fiddle
Use conditional aggregation:
SELECT TO_CHAR(MIN(GEN_DATUM),'DD.MM.YYYY') AS GRD_ROW_ID,
COUNT( DISTINCT
CASE
WHEN ART = 1
AND TRUNC(gen_datum) - TRUNC(gen_datum, 'WW') = 0
THEN LP_BELEGUNG_ID
END
) AS ANZAHL_ART_1_DAY1,
COUNT( DISTINCT
CASE
WHEN ART = 1
AND TRUNC(gen_datum) - TRUNC(gen_datum, 'WW') = 1
THEN LP_BELEGUNG_ID
END
) AS ANZAHL_ART_1_DAY2,
-- ...
COUNT( DISTINCT
CASE
WHEN ART = 1
AND TRUNC(gen_datum) - TRUNC(gen_datum, 'WW') = 6
THEN LP_BELEGUNG_ID
END
) AS ANZAHL_ART_1_DAY7,
COUNT( DISTINCT
CASE
WHEN ART = 2
AND TRUNC(gen_datum) - TRUNC(gen_datum, 'WW') = 0
THEN LP_BELEGUNG_ID
END
) AS ANZAHL_ART_2_DAY1,
COUNT( DISTINCT
CASE
WHEN ART = 2
AND TRUNC(gen_datum) - TRUNC(gen_datum, 'WW') = 1
THEN LP_BELEGUNG_ID
END
) AS ANZAHL_ART_2_DAY2,
-- ...
COUNT( DISTINCT
CASE
WHEN ART = 2
AND TRUNC(gen_datum) - TRUNC(gen_datum, 'WW') = 6
THEN LP_BELEGUNG_ID
END
) AS ANZAHL_ART_2_DAY7,
COUNT( DISTINCT
CASE
WHEN ART = 3
AND TRUNC(gen_datum) - TRUNC(gen_datum, 'WW') = 0
THEN LP_BELEGUNG_ID
END
) AS ANZAHL_ART_3_DAY1,
COUNT( DISTINCT
CASE
WHEN ART = 3
AND TRUNC(gen_datum) - TRUNC(gen_datum, 'WW') = 1
THEN LP_BELEGUNG_ID
END
) AS ANZAHL_ART_3_DAY2,
-- ...
COUNT( DISTINCT
CASE
WHEN ART = 3
AND TRUNC(gen_datum) - TRUNC(gen_datum, 'WW') = 6
THEN LP_BELEGUNG_ID
END
) AS ANZAHL_ART_3_DAY7,
COUNT( DISTINCT
CASE
WHEN ART = 99
AND TRUNC(gen_datum) - TRUNC(gen_datum, 'WW') = 0
THEN LP_BELEGUNG_ID
END
) AS ANZAHL_ART_4_DAY1,
COUNT( DISTINCT
CASE
WHEN ART = 99
AND TRUNC(gen_datum) - TRUNC(gen_datum, 'WW') = 1
THEN LP_BELEGUNG_ID
END
) AS ANZAHL_ART_4_DAY2,
-- ...
COUNT( DISTINCT
CASE
WHEN ART = 99
AND TRUNC(gen_datum) - TRUNC(gen_datum, 'WW') = 6
THEN LP_BELEGUNG_ID
END
) AS ANZAHL_ART_4_DAY7
FROM LP_BELEGUNG
WHERE TO_CHAR(GEN_DATUM, 'WW') = 37

Oracle SQL Show all month of a year, with or without value ORA-01841

I have a problem with which I despair, I have data distributed over days, and would like to display this for the entire year in months and once in weeks.
My problem with the months that I get in the select my data displayed (for January, September) but I want that all months for a selected year are displayed, even if they are empty. For this I have made myself a "WITH" (copied) and now try to join this, but get an ORA-01841 error.
And how do I implement the whole construct to display only the weeks.
WITH MONAT_ZAEHLER (MZ) AS
(
SELECT
TO_CHAR(ADD_MONTHS(TO_DATE('01.2022','MM.YYYY'),LEVEL -1),'Month', 'NLS_DATE_LANGUAGE = GERMAN') AS GRD_ROW_ID
FROM
DUAL
CONNECT BY LEVEL <= 12
)
SELECT
TO_CHAR(GEN_DATUM,'Month', 'NLS_DATE_LANGUAGE = GERMAN') AS GRD_ROW_ID
, COUNT( DISTINCT CASE
WHEN LP_BELEGUNG.ART = 1 THEN LP_BELEGUNG.LP_BELEGUNG_ID
ELSE NULL
END ) AS "1"
, COUNT( DISTINCT CASE
WHEN LP_BELEGUNG.ART = 2 THEN LP_BELEGUNG.LP_BELEGUNG_ID
ELSE NULL
END ) AS "2"
, COUNT( DISTINCT CASE
WHEN LP_BELEGUNG.ART = 3 THEN LP_BELEGUNG.LP_BELEGUNG_ID
ELSE NULL
END ) AS "3"
, COUNT( DISTINCT CASE
WHEN LP_BELEGUNG.ART = 99 THEN LP_BELEGUNG.LP_BELEGUNG_ID
ELSE NULL
END ) AS "99"
FROM
LP_BELEGUNG
FULL OUTER JOIN MONAT_ZAEHLER ON TRUNC(LP_BELEGUNG.GEN_DATUM, 'Month') = MONAT_ZAEHLER.MZ
WHERE
TO_CHAR(GEN_DATUM, 'YYYY') = '2022'
GROUP BY
TO_CHAR(GEN_DATUM,'Month', 'NLS_DATE_LANGUAGE = GERMAN')
The error is because you're converting the month to a name string in the CTE, then trying to convert it again for the GRD_ROW_ID alias.
The solution is basically the same as your previous question, but now you want the CTE to have one row per month - which you are doing, but you should leave it as a date type in the CTE, not convert it to a string there:
with cte (dt) as (
select add_months(date '2022-01-01', level - 1)
from dual
connect by level <= 12
)
... then convert that actual date value to a string:
SELECT
TO_CHAR(cte.dt, 'Month', 'NLS_DATE_LANGUAGE = GERMAN') AS GRD_ROW_ID
...
... and outer join to your actual table as before, using a date range:
FROM
cte
LEFT JOIN
LP_BELEGUNG
ON
LP_BELEGUNG.GEN_DATUM >= cte.dt AND LP_BELEGUNG.GEN_DATUM < add_months(cte.dt, 1)
GROUP BY
cte.dt
ORDER BY
cte.dt
... this time looking for values where the the GEN_DATUM is greater than or equal to cte.dt value (again, as before), which is midnight on the first day of the first day of the month; and less than add_months(cte.dt, 1), which is midnight on the first day of the first day of the following month. So for January, that will be >= 2022-01-01 00:00:00 and < 2022-02-01 00:00:00, which is all possible dates and times during that month.
GRD_ROW_ID
ANZAHL_ART_1
ANZAHL_ART_2
ANZAHL_ART_3
ANZAHL_ART_4
Januar
0
0
0
0
Februar
0
0
0
0
März
0
0
0
0
April
0
0
0
0
Mai
0
0
0
0
Juni
0
0
0
0
Juli
0
0
0
0
August
0
0
0
0
September
1
1
1
7
Oktober
0
0
0
0
November
0
0
0
0
Dezember
0
0
0
0
fiddle
To get a row for every week of the year you would do something similar again, but in blocks of 7 days:
with cte (dt) as (
select date '2022-01-01' + 7 * (level - 1)
from dual
connect by level <= 53
)
SELECT
TO_CHAR(cte.dt, 'YYYY-WW') AS GRD_ROW_ID
...
FROM
cte
LEFT JOIN
LP_BELEGUNG
ON
LP_BELEGUNG.GEN_DATUM >= cte.dt AND LP_BELEGUNG.GEN_DATUM < cte.dt + 7
AND LP_BELEGUNG.GEN_DATUM < add_months(trunc(cte.dt, 'YYYY'), 12)
GROUP BY
cte.dt
ORDER BY
cte.dt
which has an extra check in the join to stop it including data from week 53 which is actually in the following year - which I'm guessing you woudl want to do.
fiddle

My count CTE returning blanks, how can I get it return as 0?

CTE created to count the number of days left from today's date to end of current month. So my report for today (30 March 2021) did not count tomorrow's date 31 March 2021.
declare #DespatchTo Date = '03-30-2021'
WITH mycte AS
(
SELECT CAST(Convert(date,getdate()) AS DATETIME) DateValue
UNION ALL
SELECT DateValue + 1
FROM mycte
WHERE DateValue < DATEADD(d, -1, DATEADD(m, DATEDIFF(m, 0, #DespatchTo) + 1, 0)) --03-31-2021
)
SELECT SUN.Count as SunCount, SAT.Count as SatCount, WK.Count as WeekCount
FROM
(SELECT count(*) as Count
FROM mycte
WHERE DatePart("w",DateValue) = 1
group by DatePart("w",DateValue))
As SUN,
(SELECT count(*) as Count
FROM mycte
WHERE DatePart("w",DateValue) = 7
group by DatePart("w",DateValue))
As SAT,
(SELECT distinct SUM(COUNT(*)) OVER() AS Count
FROM mycte
WHERE DatePart("w",DateValue) > 1 AND DatePart("w",DateValue) < 7
group by DatePart("w",DateValue))
As WK
Which returns blank/null results. How can I return as 0?
here is what you need to do:
;WITH mycte AS (
SELECT GETDATE() DateValue
UNION ALL
SELECT DateValue + 1
FROM mycte
WHERE DateValue < EOMONTH(GETDATE())
)
select
count(case when datepart(dw, DateValue) = 1 then 1 end) SUN
, count(case when datepart(dw, DateValue) = 7 then 1 end) SAT
, count(case when datepart(dw, DateValue) between 2 and 6 then 1 end) WK
from mycte
if you want to exclude today, you can adjust cte :
;WITH mycte AS (
SELECT GETDATE() + 1 DateValue
WHERE GETDATE() <> EOMONTH(GETDATE())
UNION ALL
SELECT DateValue + 1
FROM mycte
WHERE DateValue < EOMONTH(GETDATE())
)
select
count(case when datepart(dw, DateValue) = 1 then 1 end) SUN
, count(case when datepart(dw, DateValue) = 7 then 1 end) SAT
, count(case when datepart(dw, DateValue) between 2 and 6 then 1 end) WK
from mycte

count rows before time

i have the following situation. every row has a timestamp when it was written on table. now i want to evaluate per day how many rows have been inserted before 5 am and how many after. how can that be done??
You can use the HH24 format to get the hour in 24-hour time:
select trunc(created_Date) as the_day
,sum(case when to_number(to_char(created_Date,'HH24')) < 5 then 1 else 0 end) as before_five
,sum(case when to_number(to_char(created_Date,'HH24')) >= 5 then 1 else 0 end) as after_five
from yourtable
group by trunc(created_Date)
Per USER's comment on 5:10, to show timestamps just before and after 5:
select trunc(created_Date) as the_day
,sum(case when to_number(to_char(created_Date,'HH24')) < 5 then 1 else 0 end) as before_five
,sum(case when to_number(to_char(created_Date,'HH24')) >= 5 then 1 else 0 end) as after_five
from (
-- one row januar 1 just after 5:00 a.m.
select to_Date('01/01/2015 05:10:12','dd/mm/yyyy hh24:mi:ss') as created_date from dual
union all
-- one row Januar 2 just before 5:00 a.m.
select to_Date('02/01/2015 04:59:12','dd/mm/yyyy hh24:mi:ss') as created_date from dual
)
group by trunc(created_Date);
THE_DAY, BEFORE_FIVE, AFTER_FIVE
02/01/2015, 1, 0
01/01/2015, 0, 1
Assuming your timestamp is a DATE column:
select trunc(date_written) as day
, count (case when (date_written-trunc(date_written))*24 < 5 then 1 end) before_5_count
, count (case when (date_written-trunc(date_written))*24 >= 5 then 1 end) after_5_count
from mytable
group by trunc(date_written)
select to_char(time_column, 'dd/mm/yyyy'),
sum( decode ( greatest(extract(hour from time_column), 5), extract(hour from time_column), 1, 0)) post_5,
sum( decode ( greatest(extract(hour from time_column), 5), extract(hour from time_column), 0, 1)) pre_5
from test_time
group by to_char(time_column, 'dd/mm/yyyy')

Fetch data in MS SQL 2008

I have three tables which are like:
table1
id,
created_Date
table2
id
district_ID
status_ID
table3
district_ID
district_Name
Now i need the records in following format
Srno District_name <10 days >10 and <20 days >20 days
1 xxx 12 15 20
2 yyy 8 0 2
count days as per current date
for example: if the created date is 10-08-2013 and current date is 13-08-2013 the date difference will be 3
So what should my query be? Any suggestions will be appreciated.
Thank you
table1
id created_Date
1 2013-07-12 13:32:10.957
2 2013-07-12 13:32:10.957
3 2013-08-01 10:00:10.957
4 2013-08-10 13:32:10.957
5 2013-08-10 14:32:10.957
table2
id district_ID status_id
1 1 3
2 2 3
3 2 7
4 3 4
5 4 3
table1
district_ID district_Name
1 xxx
2 yyy
3 zzz
4 aaa
5 bbb
I would have a look at using DATEDIFF and CASE.
DATEDIFF (Transact-SQL)
Returns the count (signed integer) of the specified datepart
boundaries crossed between the specified startdate and enddate.
Something like
SELECT District_name,
SUM(
CASE
WHEN DATEDIFF(day,created_Date, getdate()) < 10
THEN 1
ELSE 0
END
) [<10 days],
SUM(
CASE
WHEN DATEDIFF(day,created_Date, getdate()) >= 10 AND DATEDIFF(day,created_Date, getdate()) < 20
THEN 1
ELSE 0
END
) [>10 and <20 days],
SUM(
CASE
WHEN DATEDIFF(day,created_Date, getdate()) >= 20
THEN 1
ELSE 0
END
) [>20 days]
FROM Your_Tables_Here
GROUP BY District_name
;with cte as (
select t3.district_Name, datediff(day, t1.created_Date, getdate()) as diff
from table1 as t1 as t1
inner join table2 as t2 on t2.id = t1.id
inner join table3 as t3 on t3.district_id = t2.district_id
)
select
district_Name,
sum(case when diff < 10 then 1 else 0 end) as [<10 days],
sum(case when diff >= 10 and diff < 20 then 1 else 0 end) as [>=10 and < 20 days],
sum(case when diff >= 20 then 1 else 0 end) as [>= 20 days]
from cte
group by district_Name