How to pivot after grouping in sql - sql

select day,type,sum(type)
from table1
group by 1,2
It returned something like this
day type count(type)
2021-04-13 a 10
2021-04-13 b 5
2021-04-14 c 2
but my desired result is as follows
I would like to pivot them . how can I transform them?
2021-04-13 2021-04-14
a 10 0
b 5 0
c 0 2
Thanks

You can use conditional aggregation. Presumably, you intend:
select day,
count(*) filter (where date = '2021-04-13') as cnt_20210413,
count(*) filter (where date = '2021-04-14') as cnt_20210414
from table1
group by day;
Note that your query has sum(type), but type is then shown with the values that are non-numeric strings. Hence, confusion. I am guessing you really intend count() and not sum().

Related

SQL compares the value of 2 columns and select the column with max value row-by-row

I have table something like:
GROUP
NAME
Value_1
Value_2
1
ABC
0
0
1
DEF
4
4
50
XYZ
6
6
50
QWE
6
7
100
XYZ
26
2
100
QWE
26
2
What I would like to do is to groupby group and select the name with highest value_1. If their value_1 are the same, compare and select the max with value_2. If they're still the same, select the first one.
The output will be something like:
GROUP
NAME
Value_1
Value_2
1
DEF
4
4
50
QWE
6
7
100
XYZ
26
2
The challenge for me here is I don't know how many categories in NAME so a simple case when is not working. Thanks for help
You can use window functions to solve the bulk of your problem:
select t.*
from (select t.*,
row_number() over (partition by group order by value1 desc, value2 desc) as seqnum
from t
) t
where seqnum = 1;
The one caveat is the condition:
If they're still the same, select the first one.
SQL tables represent unordered (multi-) sets. There is no "first" one unless a column specifies the ordering. The best you can do is choose an arbitrary value when all the other values are the same.
That said, you might have another column that has an ordering. If so, add that as a third key to the order by.

SQL Group by only correlative rows

Say I have the following table:
Code A B C Date ID
------------------------------
50 1 1 A 2018-01-08 150001
50 1 1 A 2018-01-15 165454
50 1 1 B 2018-02-01 184545
50 1 1 A 2018-02-02 195487
I need the sql query to output the following:
Code A B C Min(Date) Min(ID)
-------------------------------
50 1 1 A 2018-01-08 150001
50 1 1 B 2018-02-01 184545
50 1 1 A 2018-02-02 195487
If I use standard group by, rows 1,2,4 are grouped in 1 row, and this is not that I want.
I want to select the row with MIN(date) and MIN(id) from the duplicate records that are together based on column code, A, B and C
in this case 1st 2 rows are duplicates so i want the min() row.
and 3rd and 4th row are distinct.
Note that the database is Vertica 8.1, that is very similar to Oracle or PostgreSQL
I think you would need the analytic function LAG(). Using this function, you can get the value of the previous row (or NULL if it's the first row itself). So you can check if the value on the previous row is different or not, and filter accordingly.
I'm not familiar with Vertica, but this should be the correct documentation for it: https://my.vertica.com/docs/7.0.x/HTML/Content/Authoring/SQLReferenceManual/Functions/Analytic/LAGAnalytic.htm
Please try the query below, it should do it:
SELECT l.Code, l.A, l.B, l.C, l.Date, l.ID
FROM (SELECT t.*,
LAG(t.C, 1) OVER (PARTITION BY t.Code, t.A ORDER BY t.Date) prev_val
FROM table_1 t) l
WHERE l.C != l.prev_val
OR l.prev_val IS NULL
ORDER BY l.Code, l.A, l.Date

Very special kind of AVG statement

Table example:
time a b c
-------------
12:00 1 0 1
12:00 2 3 1
13:00 3 2 1
13:00 3 3 3
14:00 1 1 1
How can I get AVG(a) from row WHERE b!=0 and AVG(c) grouped by time. Is it possible to solve with sql only? I mean that query should not count 1st row to get AVG(a), but not the same with AVG(c).
You can utilize CASE statements to get conditional aggregates:
SELECT AVG(CASE WHEN b != 0 THEN a END)
,AVG(c)
FROM YourTable
GROUP BY time
Demo: SQL Fiddle
This works because a value not captured by WHEN criteria in a CASE statement will default to NULL, and NULL values are ignored by aggregate functions.
SELECT AVG(a), AVG(c) from table WHERE b != 0
group by time
Yea... is this what you need?
You might want to try something like
SELECT T.tTIME
, AVG(CASE WHEN T.B != 0 THEN T.A END)
, AVG(T.C)
FROM #T T
GROUP BY T.tTIME
The output is the following:
tTIME (No column name) (No column name)
12:00:00.0000000 2 1
13:00:00.0000000 3 2
14:00:00.0000000 1 1

To find total number of rows

I have a table like this
Table1
=======
A B
8 5
2 9
null 4
2 5
How to find total number of rows from table1,note if any column value is null in a row then that row should be considered as 2 rows?
I have tried with count(*)*2 and nvl function it doesn't work
Try this
SELECT SUM(CASE WHEN A IS NULL OR B IS NULL THEN 2 ELSE 1 END) AS CountVal
FROM TABLE1
Fiddle Demo
O/P:
COUNTVAL
--------
5
COUNT() is rowbased.. you can tweak it using SUM() instead..
select sum(NVL2(a,NVL2(b,1,2),2)) FROM TABLE1
CASE as suggested by #Vignesh is the simplest and more readable !!
COUNT() can also done like this.. But NOT a optimal solution at all!
SELECT COUNT(1) FROM
(
SELECT NVL(a,NVL(b,1)) FROM TABLEA
UNION ALL
SELECT NVL(a,NVL(b,1)) FROM TABLEA
WHERE A OR B iS NULL
)

TOP 1 Query from each ID with multiple instances

This query will return the top for all rows in MS Access.
SELECT TOP 1 * FROM [table]
ORDER BY table.[Date] DESC;
I need to return the top date for each id that can have multiple dates.
ID DATE
1 01/01/2001
1 01/12/2011
3 01/01/2001
3 01/12/2011
Should return only the top dates like this.
1 01/12/2011
3 01/12/2011
You'll want to use the MAX function, along with a GROUP BY.
SELECT ID, MAX(DATE)
FROM [table]
GROUP BY ID