How to query all months from January to December - sql

How to query all months from January to December for all values. The values of 0 should also be presented in query result.
My query:
SELECT *
FROM
(SELECT
MONTH(begin_ts) AS [Month],
SUM(CASE
WHEN bmktonr = '7'
THEN dauer
ELSE reserve1
END) + SUM(CASE
WHEN bmktonr = '11'
THEN dauer
ELSE reserve1
END) AS Prozess_Verfügbarkeit,
SUM(CASE
WHEN bmktonr = '1'
THEN dauer
ELSE reserve1
END) + SUM(CASE
WHEN bmktonr = '2'
THEN dauer
ELSE reserve1
END) AS Verfügbarkeit
FROM
[hydra1].[hydadm].[v_ereignis]
WHERE
masch_nr = 'FIMI1'
AND YEAR(begin_ts) = YEAR(CURRENT_TIMESTAMP)
GROUP BY
MONTH(begin_ts)) T
INNER JOIN
(SELECT
p.masch_nr,
SUM(b.ruest_zeit) AS SOLLRüsten,
SUM(b.bearb_zeit) AS SOLLProduktion,
SUM(b.ruest_zeit_zuschl) AS SOLLZuschlag,
SUM(p.bmk_07) AS ISTRüsten,
SUM(p.bmk_11) AS ISTProduktion,
MONTH(prot_dat) AS Month
FROM
[hydra1].[hydadm].[v_auftrag_status] p
JOIN
[hydra1].[hydadm].[v_auftrags_bestand] b ON b.auftrag_nr = p.auftrag_nr
WHERE
p.masch_nr = 'GEORG'
AND a_status = 'E'
AND YEAR(prot_dat) = YEAR(CURRENT_TIMESTAMP)
GROUP BY
p.masch_nr, MONTH(prot_dat)) T1 ON T.Month = T1.Month
ORDER BY
T.Month
This is how it should look then:
Month | Prozess_Verfügbarkeit | Verfügbarkeit
------+-----------------------+--------------
1 | 344 | 4556
2 | 0 | 0
3 | 0 | 0
4 | 0 | 0
5 | 0 | 0
6 | 0 | 0
7 | 0 | 0
8 | 0 | 0
9 | 0 | 0
10 | 0 | 0
11 | 0 | 0
12 | 0 | 0
Thanks a lot.

Something like this ought to do it:
WITH months AS (
SELECT 1 AS month_number
UNION ALL SELECT 2
UNION ALL SELECT 3
...
UNION ALL SELECT 12
)
SELECT months.month_number
, your_query.thing_a
, your_query.thing_b
FROM months
LEFT
JOIN your_query
ON your_query.Month = months.month_number
;

Related

SQL Query for below scenario for multiple rows

Need response as per expected result column in attached image.
The row filtration is required in multiple rows
The rule is (x.attr2 = '1' AND x.attr3 = '1') AND (x.attr2='' AND x.attr3='2') then its expected column value is true but all other conditions its false
Its MS SQL
Key Atr2 Atr3 expected result
111 1 1 TRUE
111 2 2
112 1 4 FALSE
113 1 4 FALSE
113 2 2
114 1 1 FALSE
Check the below script-
IF OBJECT_ID('[Sample]') IS NOT NULL
DROP TABLE [Sample]
CREATE TABLE [Sample]
(
[Key] INT NOT NULL,
Attr1 INT NOT NULL,
Attr2 INT NOT NULL,
Attr3 INT NOT NULL
)
GO
INSERT INTO [Sample] ([Key],Attr1,Attr2,Attr3)
VALUES (111,62,1,1),
(111,62,2,2),
(112,62,1,4),
(113,62,1,4),
(113,62,2,2),
(114,62,1,1)
--EXPECTED_RESULT:
SELECT S.*,CASE WHEN T.[KEY] IS NOT NULL THEN 'TRUE' ELSE 'FALSE' END AS Expected_Result
FROM [Sample] S LEFT JOIN
(
SELECT T.[KEY] FROM
(
SELECT x.*,
ROW_NUMBER() OVER( PARTITION BY x.[KEY],x.attr1 ORDER BY x.attr2,x.attr3) AS r_no
--,CASE WHEN (x.attr2 = 1 AND x.attr3 = 1) OR (x.attr2 = 2 AND x.attr3 = 2)
--then 'TRUE' else 'FALSE' end as expected_result
FROM [Sample] x WHERE x.attr2=x.attr3
) T WHERE T.r_no>1
) T ON S.[KEY]=T.[KEY]
This query:
select key from tablename
group by key
having sum(case when atr2 = '1' and atr3 = '1' then 1 else 0 end) > 0
and sum(case when atr2 = '2' and atr3 = '2' then 1 else 0 end) > 0
and count(*) = 2
uses conditional aggregation to find the keys for which the result should be true.
So join it to the table like this:
select t.*,
case when g.[key] is null then 'FALSE' else 'TRUE' end result
from tablename t left join (
select [key] from tablename
group by [key]
having sum(case when atr2 = '1' and atr3 = '1' then 1 else 0 end) > 0
and sum(case when atr2 = '2' and atr3 = '2' then 1 else 0 end) > 0
and count(*) = 2
) g on g.[key] = t.[key]
See the demo.
Results:
> Key | Atr2 | Atr3 | result
> --: | ---: | ---: | :-----
> 111 | 1 | 1 | TRUE
> 111 | 2 | 2 | TRUE
> 112 | 1 | 4 | FALSE
> 113 | 1 | 4 | FALSE
> 113 | 2 | 2 | FALSE
> 114 | 1 | 1 | FALSE

SQL count condition with 12months table

I have the following table Named: LISTON
| TYPE | MONTHS | New | Old |
+------+--------+-----+-----+
| A | FEB | Y | N |
| A | MAY | Y | N |
| A | MAY | N | Y |
| B | MAY | Y | N |
| A | MAY | Y | N |
| C | MAY | Y | N |
| D | MAY | Y | N |
I would like to arrange the data above into the format shown below:
| MONTHS | A | B | C | D |
| | New | Old | New | Old | New | Old | New | Old |
+--------+-----+-----+-----+-----+-----+-----+-----+-----+
| JAN | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| FEB | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| MAR | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| APR | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| MAY | 2 | 1 | 1 | 0 | 1 | 0 | 1 | 0 |
Is it possible to do that in SQL? by count or by sorting? Or any other ways would be helpful.
You can try this code:
with
MyTable as
( select 'A' as type, 'FEB' as months, 'Y' as new, 'N' as old from dual
union all select 'A', 'MAY', 'Y', 'N' from dual
union all select 'A', 'MAY', 'N', 'Y' from dual
union all select 'B', 'MAY', 'Y', 'N' from dual
union all select 'A', 'MAY', 'Y', 'N' from dual
union all select 'C', 'MAY', 'Y', 'N' from dual
union all select 'D', 'MAY', 'Y', 'N' from dual
)
select *
from MyTable
pivot ( count(decode(new, 'Y', 1, null)) as new
, count(decode(old, 'Y', 1, null)) as old
for type in ('A' a, 'B' b, 'C' c, 'D' d)
)
Order by 1
you can do this with pivot, e.g.
with pvt as(select * from mtable
pivot (
sum(case new when 'Y' then 1 else 0 end) new,
sum(case old when 'Y' then 1 else 0 end) old
for atype in ('A' a, 'B' b, 'C' c, 'D' d)
)
order by to_char(to_date(months, 'MON'), 'mm')),
mnt as (select level mid, to_char(to_date(to_char(level,'09'),'mm'),'MON') months from dual connect by level <= 12)
select months, nvl(a_new,0) a_new, nvl(a_old,0) a_old,
nvl(b_new,0) b_new, nvl(b_old,0) b_old,
nvl(c_new,0) c_new, nvl(c_old,0) c_old,
nvl(d_new,0) d_new, nvl(d_old,0) d_old
from mnt
left outer join pvt using (months)
order by mnt.mid;
This gives output like:
MONTHS A_NEW A_OLD B_NEW B_OLD C_NEW C_OLD D_NEW D_OLD
------+-----+-----+-----+-----+-----+-----+-----+-----
JAN 0 1 0 0 1 0 0 0
FEB 0 1 0 0 0 0 0 1
MAR 0 0 0 0 1 0 1 0
APR 0 0 0 0 0 0 0 1
MAY 0 1 0 0 0 0 0 0
JUN 0 0 0 0 0 1 1 0
JUL 0 0 0 0 0 0 0 0
AUG 0 2 0 0 0 0 1 0
SEP 0 1 0 0 0 0 0 1
OCT 0 0 0 0 0 0 0 0
NOV 0 0 0 0 0 0 0 0
DEC 1 0 0 2 0 1 0 1
You can do this using SUM CASE WHEN conditions as given below.
SELECT MONTHS,
SUM(CASE WHEN A.TYPE = 'A' AND A.NEW = 'Y' THEN 1 ELSE 0 END) AS A_NEW,
SUM(CASE WHEN A.TYPE = 'A' AND A.OLD = 'Y' THEN 1 ELSE 0 END) AS A_OLD,
SUM(CASE WHEN A.TYPE = 'B' AND A.NEW = 'Y' THEN 1 ELSE 0 END) AS B_NEW,
SUM(CASE WHEN A.TYPE = 'B' AND A.OLD = 'Y' THEN 1 ELSE 0 END) AS B_OLD,
SUM(CASE WHEN A.TYPE = 'C' AND A.NEW = 'Y' THEN 1 ELSE 0 END) AS C_NEW,
SUM(CASE WHEN A.TYPE = 'C' AND A.OLD = 'Y' THEN 1 ELSE 0 END) AS C_OLD,
SUM(CASE WHEN A.TYPE = 'D' AND A.NEW = 'Y' THEN 1 ELSE 0 END) AS D_NEW,
SUM(CASE WHEN A.TYPE = 'D' AND A.OLD = 'Y' THEN 1 ELSE 0 END) AS D_OLD
FROM
MYTABLE A
GROUP BY MONTHS;
You can manage it by using pivot clause :
with tab as
(
select mon, type||new||old type from months m1 right outer join
( select to_char(to_date(lpad(level,2,'0'),'MM'),'MON') mon, level mon_nr from dual
connect by level <= 5 ) m2 on ( m1.month = m2.mon ) -- you can replace 5 with 12 for whole year
)
select * from tab
pivot
(
count(1) for (type) in ('AYN' as "A (New)",'ANY' as "A (Old)",'BYN' as "B (New)",'BNY' as "B (Old)",'CYN' as "C (New)",'CNY' as "C (Old)",'DYN' as "D (New)",'DNY' as "D (Old)")
)
order by to_date(mon,'MM');
where the months table is created as below :
create table months(Type varchar2(1),Month varchar2(3),New varchar2(1),Old varchar2(1));
and the output is:
MON A (New) A (Old) B (New) B (Old) C (New) C (Old) D (New) D (Old)
JAN 0 0 0 0 0 0 0 0
FEB 1 0 0 0 0 0 0 0
MAR 0 0 0 0 0 0 0 0
APR 0 0 0 0 0 0 0 0
MAY 2 1 1 0 1 0 1 0
D e m o
Since you tagged your post with plsql, I'm assuming you are using Oracle database.
From your description, it looks to me that you want to convert rows into columns. This can be done in Oracle using what's known as a pivot. This Web page shows you how to write a pivot query. Hope it helps.
Good Luck,
Avi.

Select As Status If Subtable Lines Include Value

I have 2 Table named Order and OrderDetails
Order Table
orderID orderDate OrderUserId
1 10 01.01.2010 .....
2 20 05.05.2011 .....
OrderDetails Table
DetailID OrderIdOfDetail DetailProductID DetailStatusID
1 25 10 xxx 1
2 26 10 xxx 2
3 27 10 xxx 2
4 28 10 xxx 0
5 29 10 xxx 1
6 30 20 xxx 1
7 31 20 xxx 2
8 32 20 xxx 0
DetailStatusId for closed , pending, cancelled bla...
For example I want to select orderID : 10.
If detail lines include DetailsStatusID 1 select order Status as "Pending".
If detail lines include DetailsStatusID 2 select order Status as "Open".
If all DetailsStatusID is equal and 0 select order status as "Closed"
I tried "if exist" but couldn't success.
How can I do it ?
You can use a query like the following:
SELECT o.orderID,
CASE
WHEN MAX(CASE WHEN DetailStatusID = 1 THEN 1 ELSE 0 END) +
MAX(CASE WHEN DetailStatusID = 2 THEN 1 ELSE 0 END) +
MAX(CASE WHEN DetailStatusID = 0 THEN 1 ELSE 0 END) >= 2
THEN 'MultiStatus'
WHEN COUNT(CASE WHEN DetailStatusID = 1 THEN 1 END) > 0 THEN 'Pending'
WHEN COUNT(CASE WHEN DetailStatusID = 2 THEN 1 END) > 0 THEN 'Open'
WHEN MAX(DetailStatusID) = 0 THEN 'Closed'
END AS Status
FROM Order AS o
JOIN OrderDetails AS od ON o.orderID = od.OrderIdOfDetail
GROUP BY orderID
The query uses a CASE expression in order to calculate the Status field:
It first checks whether the order contains at least one record with DetailStatusID = 1. If it does 'Pending' is returned.
It then checks whether the order contains at least one record with DetailStatusID = 2. If it does 'Open' is returned.
It then checks whether all records of the group have DetailStatusID = 0. In this case 'Closed' is returned. I assume that DetailStatusID cannot take negative vaues.
This uses a left join to an derived table (subquery) that uses conditional aggregation to count the different DetailStatusId. This will also return a result of Other for Status if, for some reason, the OrderId has no corresponding details record.
select o.*
, [Status]=case
when od.Status0 > 0 and od.Status0 = od.DetailCount
then 'Closed'
when od.Status1 > 0
then 'Pending'
when od.Status2 > 0
then 'Open'
else 'Other'
end
from orders as o
left join (
select
OrderIdOfDetail
, DetailCount = count(*)
, Status0 = sum(case when DetailStatusId = 0 then 1 else 0 end)
, Status1 = sum(case when DetailStatusId = 1 then 1 else 0 end)
, Status2 = sum(case when DetailStatusId = 2 then 1 else 0 end)
from OrderDetails
group by OrderIdOfDetail
) as od
on o.OrderId = od.OrderIdOfDetail
rextester demo: http://rextester.com/YPA79670
query results:
+---------+---------------------+-------------+---------+
| orderID | orderDate | OrderUserId | Status |
+---------+---------------------+-------------+---------+
| 10 | 01.01.2010 00:00:00 | 1 | Pending |
| 20 | 05.05.2011 00:00:00 | 2 | Pending |
+---------+---------------------+-------------+---------+
subquery only results:
+-----------------+-------------+---------+---------+---------+
| OrderIdOfDetail | DetailCount | Status0 | Status1 | Status2 |
+-----------------+-------------+---------+---------+---------+
| 10 | 5 | 1 | 2 | 2 |
| 20 | 3 | 1 | 1 | 1 |
+-----------------+-------------+---------+---------+---------+
select *, case when DetailStatusID = '1' then 'Pending'
when DetailStatusID = '2' then 'Open'
when DetailStatusID = '0' then 'Closed'
end as OrderStatusDescription
From OrderDetails
Where OrderIdOfDetail = '10'

SQL check if column contains specific values

I have a table like this:
id | Values
------------------
1 | a
1 | b
1 | c
1 | d
1 | e
2 | a
2 | a
2 | c
2 | c
2 | e
3 | a
3 | c
3 | b
3 | d
Now I want to know which id contains at least one of a, one of b and one of c.
This is the result I want:
id
--------
1
3
One method is aggregation with having:
select id
from t
where values in ('a', 'b', 'c')
group by id
having count(distinct values) = 3;
If you wanted more flexibility with the counts of each value:
having sum(case when values = 'a' then 1 else 0 end) >= 1 and
sum(case when values = 'b' then 1 else 0 end) >= 1 and
sum(case when values = 'c' then 1 else 0 end) >= 1
You can use grouping:
SELECT id
FROM your_table
GROUP BY id
HAVING SUM(CASE WHEN value = 'a' THEN 1 ELSE 0 END) >= 1
AND SUM(CASE WHEN value = 'b' THEN 1 ELSE 0 END) = 1
AND SUM(CASE WHEN value = 'c' THEN 1 ELSE 0 END) = 1;
or using COUNT:
SELECT id
FROM your_table
GROUP BY id
HAVING COUNT(CASE WHEN value = 'a' THEN 1 END) >= 1
AND COUNT(CASE WHEN value = 'b' THEN 1 END) = 1
AND COUNT(CASE WHEN value = 'c' THEN 1 END) = 1;

How to group sums by weekday in MySQL?

I have a table like this:
id | timestamp | type
-----------------------
1 2010-11-20 A
2 2010-11-20 A
3 2010-11-20 B
4 2010-11-21 A
5 2010-11-21 C
6 2010-11-27 B
and I need to count the rows for each type, grouped by weekday; like this:
weekday | A | B | C
--------------------------
5 2 2 0 -- the B column equals 2 because nov 20 and nov 27 are saturday
6 1 0 1
What would be the simplest solution for this?
I don't mind using views, variables, subqueries, etc.
Use:
SELECT WEEKDAY(t.timestamp) AS weekday,
SUM(CASE WHEN t.type = 'A' THEN 1 ELSE 0 END) AS a,
SUM(CASE WHEN t.type = 'B' THEN 1 ELSE 0 END) AS b,
SUM(CASE WHEN t.type = 'C' THEN 1 ELSE 0 END) AS c
FROM YOUR_TABLE t
GROUP BY WEEKDAY(t.timestamp)