Oracle SQL count colums and group by date - sql

Hi I have a table like this one
C_DATE SOURCE
11/21/2012 A
11/22/2012 A
11/22/2012 A
11/22/2012 A
11/23/2012 A
11/23/2012 A
11/25/2012 A
11/26/2012 A
11/26/2012 B
11/26/2012 B
11/26/2012 B
11/21/2012 B
11/22/2012 B
11/22/2012 B
11/23/2012 B
11/23/2012 C
11/24/2012 C
11/24/2012 C
11/24/2012 C
11/24/2012 C
11/25/2012 C
How can I have the count by source and by date as follows:
c_date source a source b source c
11/21/2012 1 4 0
11/22/2012 1 1 1
11/23/2012 0 0 1
11/24/2012 and so on..
The closest I have got is something like
select trunc(c_date) XDATE,
(select count(**) from TABLE where source='A') A,
(select count(**) from TABLE where source='B') B,
(select count(*) from TABLE where source='C') C
from TABLE
group by trunc(C_DATE)
order by trunc(C_DATE) asc
but it repeats the total count for each row I cannot find how to relate the count colums with the date.
Thanks a lot for your help

select trunc(c_date) XDATE,
sum(case source when 'A' then 1 else 0 end) cnt_a,
sum(case source when 'B' then 1 else 0 end) cnt_b,
sum(case source when 'C' then 1 else 0 end) cnt_c,
from TABLE
group by trunc(C_DATE)
order by trunc(C_DATE) asc
update as long as you use 11g, you can use modern pivot clause :)
select xdate, a, b, c
from
(select trunc(c_date) XDATE, source, count(*)
from tab
group by trunc(c_date), source )
pivot
( count(*) for source in ('A' a, 'B' b, 'C' c) )
order by 1;
http://sqlfiddle.com/#!4/d0269/16

Related

Sum a column based on a condition in another column with partitions

I'm trying to sum a column based on a condition in another column with partition by in SQL, but it's not working. So I hope somebody can help me with this.
My table is like this:
Group_1
Group_2
Date
Value
A
D
01/01/2021
1
A
D
01/02/2021
3
A
E
01/03/2021
5
B
D
01/01/2021
7
B
D
01/02/2021
9
B
E
01/03/2021
11
B
D
01/05/2021
17
B
D
01/03/2021
13
B
E
01/04/2021
13
C
D
01/01/2021
7
C
D
01/02/2021
10
So, I need to sum the values of [Value] for all rows where there is a 'D' on [Group_2] that is older than the first 'E' on the same group (if it exists) for each group of [Group_1].
And the result should be like:
Group_1
Group_2
Sum
A
D
4
B
D
16
C
D
17
Anybody knows how can I solve this kind of problem?
Try the following aggregation with NOT EXISTS:
SELECT Group_1, Group_2, SUM(Value) AS Value_Sum
FROM table_name T
WHERE Group_2 <> 'E' AND
NOT EXISTS (SELECT 1 FROM table_name D
WHERE D.Group_1 = T.Group_1 AND
D.Group_2 = 'E' AND
D.Date <= T.Date)
GROUP BY Group_1, Group_2
ORDER BY Group_1, Group_2
See a demo.
select group_1
,group_2
,sum(value)
from
(
select group_1
,group_2
,case when count(case when group_2 = 'E' then 1 end) over(partition by group_1 order by date) = 0 then value end as value
from t
) t
group by group_1, group_2
having group_2 = 'D'
group_1
group_2
sum
A
D
4
B
D
16
C
D
17
Fiddle

pivot rows certain values to columns

i have this table,
id activity type start_date
1 a type_o 01/01/20
1 b type_o 05/01/20
1 c type_o 07/01/20
1 d type_o 23/01/20
1 e type_o 24/01/20
2 a type_k 08/01/20
2 b type_k 10/01/20
2 c type_k 11/01/20
2 d type_k 12/01/20
3 a type_h 12/01/20
3 c type_h 13/01/20
3 e type_h 14/01/20
all activities are (a,b,c,d,e)
i want it to look like this,
id type a b c d e
1 type_o 01/01/20 05/01/20 07/01/20 23/01/20 24/01/20
2 type_k 08/01/20 10/01/20 11/01/20 null null
3 type_h 12/01/20 null 13/01/20 null 12/01/20
where we compensate null in other activities not exists in some id's,
i don't understand the pivot keyword in sql, any help ?
You must be looking for this:
SELECT * FROM
(SELECT * FROM YOUR_TABLE)
PIVOT
(MAX(START_DATE) as START_DATE FOR ACTIVITY IN ('a' as a, 'b' as b, 'c' as c, 'd' as d, 'e' as e))
A more universal solution is to use CASE - WHEN statements.
The advantage is - the code is more portable across different SQL flavours and you can take care of duplicates in the records, if needed down the line.
select id,type
,case when activity = 'a' then min(start_date) else null end as `a`
,case when activity = 'b' then min(start_date) else null end as `b`
,case when activity = 'c' then min(start_date) else null end as `c`
,case when activity = 'd' then min(start_date) else null end as `d`
group by 1,2
Use conditional aggregation:
select id, type,
max(case when activity = 'a' then start_date end) as a,
max(case when activity = 'b' then start_date end) as b,
max(case when activity = 'c' then start_date end) as c,
max(case when activity = 'd' then start_date end) as d,
max(case when activity = 'e' then start_date end) as e
from thistable
group by id, type;

split data in a table into 2 columns based on conditions

got to split a column in my table into 2 based on conditions.All in a select clause.
my table has a column as detail_code. There are 2 detail codes .I want each detail code as a separate column in my select clause.
I tried subquery but it throws subquery returns more than one row.
select id,(select detail_code from detc where type_ind ='C')as Detail_code1,
(select detail_code from detc where type_ind ='P')as Detail_code2,
(Select sum(amount) from amount_tbl where detail_code in (select detail_code from detc where type_ind ='C')and term_code='2019')as amt_detail_code1
from id_table;
My output should be
Id Detail_code1 Detail_code2 sum(amt_Detail_Code1) sum(amt_Detail_code2)
1 C P 15 45
2 C P 785 74
My input
ID Detail_cd ind amt
317002687 CA20 C 3
317002687 CA21 C 60
317002687 CA23 C 18.75
317002687 CA25 C 179.64
317002687 CA26 C 136.5
317002687 CA27 C 8.25
317002687 CA28 C 4
317002687 CA2B C 8
317002687 CA2H C 6.75
317002687 CA2I C 237
317002687 CA2J C 65.4
This query would produce the output you describe:
SELECT id, 'C' AS detail_code1, 'P' AS detail_code2,
SUM(CASE WHEN ind = 'C' THEN amt END) AS sum_detail_code1,
SUM(CASE WHEN ind = 'P' THEN amt END) AS sum_detail_code2
FROM name_of_your_input_table
GROUP BY id;
Alternatively, since you know what the two detail codes are, you could make those the column names and have the value of each column be the average for that detail code. One way to do this is to pivot. Here's the Oracle syntax:
SELECT *
FROM (SELECT id, ind AS detail_code, amt
FROM name_of_your_input_table)
PIVOT (AVG(amt)
FOR detail_code IN ('C', 'P'));

sql query to get multiple data through date

table ta having four columns ( SQL server and D column is date)
A | B | C|D
1 |11| 0|10-MAY-2019
1 |12| 0|10-MAY-2019
1 |13| 0|null
2 |33| 5|null
2 |34| 10|null
2 |35| 78|null
5 |45| 0|10-MAY-2019
5 |49| 0|10-MAY-2019
5 |51| 0|10-MAY-2019
8 |10| 0|1-MAY-2018
8 |14| 0|1-MAY-2018
8 |34| 0|1-MAY-2018
I am looking the SQL query to fetch the distinct A value which is having C value ZERO for all the B (ie. SUM(ABS(C))=0) and all D value for that will not be null and should be > GETDATE() - 90 (i.e any day between current date and 90 days)
From above table I would only get the value of A as '5'
Try this-
SELECT * FROM
(
SELECT A
FROM your_table
WHERE D > CAST(DATEADD(DD,-90,GETDATE()) AS DATE)
GROUP BY A
HAVING COUNT(A) = SUM(CASE WHEN C= 0 THEN 1 ELSE 0 END)
)A
WHERE NOT EXISTS
(
SELECT 1 FROM your_table B WHERE A.A = B.A
AND D IS NULL
)
You can use aggregation. I think this is the logic you describe:
select a
from t
where d > dateadd(day, -90, getdate()) or d is null
group by a
having max(c) = 0 and
count(*) = count(d); -- no NULL d values

Display 0 when count(*) is zero for a group by clause

I am trying to write a SQL query which can display value as 0 if there are no rows for the specified condition
I have tried the following so far but nothing seems to work
coalesce(count(m.a),'0')
isnull(count(m.a),'0')
case when count(*) > 0 then count(*) else '0' end
select M.a, m.b, m.c, m.d, m.e,
--coalesce(count(m.a),'0') as CountOfRecords
--isnull(count(m.a),'0') as CountOfRecords
--case when count(*) > 0 then count(*) else '0' end
from my_table M
left join
(select a, b,c,d,e
from my_table
group by a, b,c,d,e
having count(*) >1 ) B
on M.b = B.b
and M.c = B.c
and M.d = B.d
and M.e = B.e
and m.a <> B.a
where M.a in (1,2)
and M.date<= '1/1/2019'
group by M.a, m.b, m.c, m.d, m.e
Expected Result
A B C D E count
1 1 1 1 1 10
2 2 2 2 2 0
Actual Result
A B C D E count
1 1 1 1 1 10
You need to use a nested request:
select coalesce(nb, 0) from (
select count(*) nb from my_table
group by my_table.a
) nested;
Are you looking for something like this?
select a, b, c, d, e,
sum(case when M.date <= '2019-01-01' then 1 else 0 end) as cnt
from my_table
where a in (1, 2)
group by a, b, c, d, e;
This keeps all rows in the original data that match the condition on a, but not necessarily the condition on the date. It then counts only the rows that match the date.