Same query with different parameters - sql

I have a query to calculate a sum over last 12 months like:
select part_no,
count(part_no) r12
from t1
where (t1.created<=sysdate and t1.created>=add_months(sysdate,-12)
Is it possible to create a query that also shows rolling 6 and rolling 3 in the same query like:
part_no r12 r6 r3
-----------------
100 8 2 1
200 12 1 0
300 10 4 4

If you just want to know COUNT of all items for last 12, 6 and 3 you can change your query as follows.
SELECT part_no
,COUNT(CASE WHEN t1.created <= sysdate
AND t1.created >= add_months(sysdate, -12) THEN 1
ELSE NULL
END) r12
,COUNT(CASE WHEN t1.created <= sysdate
AND t1.created >= add_months(sysdate, -6) THEN 1
ELSE NULL
END) r6
,COUNT(CASE WHEN t1.created <= sysdate
AND t1.created >= add_months(sysdate, -3) THEN 1
ELSE NULL
END) r3
FROM t1
GROUP BY part_no

You can calculate date difference (in months) in subquery and group by it. But don't forget about query performance.

You probably can try something like this:
SELECT part_no,
SUM( IF(t1.created>=add_months(sysdate,-12), 1, 0) ) r12,
SUM( IF(t1.created>=add_months(sysdate,-6), 1, 0) ) r6,
SUM( IF(t1.created>=add_months(sysdate,-3), 1, 0) ) r3
FROM t1
WHERE t1.created<=sysdate
GROUP BY part_no

Related

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

select multiple rows group by date interval ( causes duplicates) [duplicate]

This question already has answers here:
retrieve multible columns group by date intervall
(2 answers)
Closed 2 years ago.
I'm trying to retrieve weight data summed over the first 15 days of a month and another 15 days of that month.
Like the table below .
here is my code,
SELECT * from
( select SUM(B.SCALE_WEIGHT) as Mtrl1 FROM TRACK2.LOG2_TAB B
where B.SCALE_EVENTDATE >= date '2020-09-01'
and B.SCALE_EVENTDATE < date '2020-09-30'
AND B.Scale_EVENTDATE = B.SCALE_EVENTDATE
and MTRLID_EXT = 206
group by floor(extract(day from SCALE_EVENTDATE)/16) ) ,
( select SUM(B.SCALE_WEIGHT) as Mtrl2 FROM TRACK2.LOG2_TAB B
where B.SCALE_EVENTDATE >= date '2020-09-01'
and B.SCALE_EVENTDATE < date '2020-09-30'
AND B.Scale_EVENTDATE = B.SCALE_EVENTDATE
and MTRLID_EXT = 211
group by floor(extract(day from SCALE_EVENTDATE)/16) )
but the result is shown in the image below, the data is duplicated ! and missing Date column
I think you want conditional aggregation:
select
floor(extract(day from scale_eventdate)/16) as fortnight,
sum(case when mtrlid_ext = 206 then scale_weight else 0 end) as mtrl1,
sum(case when mtrlid_ext = 211 then scale_weight else 0 end) as mtrl2
from track2.log2_tab
where
mtrlid_ext in (206, 211)
and scale_eventdate >= date '2020-09-01'
and scale_eventdate < date '2020-10-01'
group by floor(extract(day from scale_eventdate) / 16)
Note that I fixed the date filtering; if you want the entire month of September, then the second condition should be: < date '2020-10-01'.

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')

How to show different dates data (from the same table) as columns in Oracle

I'm sorry if the title wasn't too clear, but the following explanation will be more accurate.
I have the following view:
DATE USER CONDITION
20140101 1 A
20140101 2 B
20140101 3 C
20140108 1 C
20140108 3 B
20140108 2 C
What I need to do is present how many users where in all conditions this week and 7 days before today.
Output should be like this:
Condition Today Last_Week (Today-7)
A 0 1
B 1 1
C 2 1
How can I do this in Oracle? I will need to do this for 4 weeks so itll be Today-7,14-21.
I've tried this with group by but I get the "week2" as rows. Then I've tried something like Select conditions, (select count(users) from MyView where DATE='Today') FROM MyView(looking at something thats actually working) but it doesnt work for me.
Achieved this with a little modification of the accepted answer:
select condition,
count(case when to_date(xdate) = to_date(sysdate) then 1 end) to_day,
count(case when to_date(xdate) = to_date(sysdate-7) then 1 end) last_7_days
from my_table
group by condition
select condition, count(case when to_date(xdate) = to_date(sysdate) then 1 end) to_day,
count(case when to_date(xdate) < to_date(sysdate) then 1 end) last_7_days
from my_table
where to_date(xdate) >= to_date(sysdate) - 7
group by condition
select condition
, sum
( case
when date between trunc(sysdate) - 7 and trunc(sysdate) - 1
then 1
else 0
end
)
last_week
, sum
( case
when date between trunc(sysdate) and trunc(sysdate + 1)
then 1
else 0
end
)
this_week
from table
group
by condition
By using the conditional count (as a sum) and grouping on condition you can filter out all desired dates. Note that using trunc will cause to use the begin of the day.

Postgres query to get data datewise

I am using PostgreSQL.
I have a table like below:
ID product_id Date Qty
-----------------------------------
1 12 2008-06-02 50
2 3 2008-07-12 5
3 12 2009-02-10 25
4 10 2012-11-01 22
5 2 2011-03-25 7
Now I want the result like below (i.e product wise sum of qty field of last 4 years):
product_id
QTY(current_year)
QTY( current year + last_year)
QTY_last2_years
QTY > 2 years
SELECT product_id
,sum(CASE mydate >= x.t THEN qty END) AS qty_current_year
,sum(CASE mydate >= (x.t - interval '1 y') THEN qty END) AS qty_since_last_year
,sum(CASE mydate >= (x.t - interval '2 y')
AND mydate < x.t THEN qty END) AS qty_last_2_year
,sum(CASE mydate < (x.t - interval '2 y') THEN qty END) AS qty_older
FROM tbl
CROSS JOIN (SELECT date_trunc('year', now()) AS t) x -- calculate once
GROUP BY 1;
To resuse the calculated beginning of the current year I CROSS JOIN it as subquery x.