SQL - after sorting, return only rows with certain consecutive values in a column - sql

I have columns name, timestamp, doing. I've already sorted by name, then by timestamp, and I expect that moving down the doing column within a group with the same name looks like A, A, A, B, B, A, A, ... - alternating series of A and B. I need to get only the rows which comprise the first B row after a transition from A to B within a group with the same name.
name timestamp doing
1 1 A
1 2 A
1 3 B
1 4 B
1 5 A
2 2 B
2 4 A
2 6 B
2 8 A
I would like to return
name timestamp doing
1 3 B
2 6 B
But not
2 2 B
because it is not a transition from A to B within name = 2

I think you just want lag():
select t.*
from (select t.*,
lag(doing) over (partition by name order by timestamp) as prev_doing
from t
) t
where prev_doing = 'A' and doing = 'B';

Related

How can I select rows corresponding to the unique pair of column values with the highest value of another column in PostgreSQL?

My table looks like this:
A
B
X
1
1
1
1
1
2
1
1
3
1
2
1
1
2
2
2
2
1
2
2
2
2
2
3
I need to select the row with the highest value in X column for each unique A, B pair.
The result would be:
A
B
X
1
1
3
1
2
2
2
2
3
I would recommend distinct on:
select distinct on (a, b) t.*
from t
order by a, b, x desc;
This allows you to select other columns from the rows, other than a, b, and x.
With an index on (a, b, x desc), this would typically be the fastest solution.
You can use the MAX aggregate function as follows:
select A, B, MAX(X) AS X
from YOUR_TABLE
group by A, B
That would work like that:
select * from a where x = (select max(x) from a)

SQL query to find the entries corresponding to the maximum count of each type

I have a table X in Postgres with the following entries
A B C
2 3 1
3 3 1
0 4 1
1 4 1
2 4 1
3 4 1
0 5 1
1 5 1
2 5 1
3 5 1
0 2 2
1 2 3
I would like to find out the entries having maximum of Column C for every kind of A and B i.e (group by B) with the most efficient query possible and return corresponding A and B.
Expected Output:
A B C
1 2 3
2 3 1
0 4 1
0 5 1
Please help me with this problem . Thank you
demo: db<>fiddle
Using DISTINCT ON:
SELECT DISTINCT ON (B)
A, B, C
FROM
my_table
ORDER BY B, C DESC, A
DISTINCT ON gives you exactly the first row for an ordered group. In this case B is grouped.
After ordering B (which is necessary): We first order the maximum C (with DESC) to the top of each group. Then (if there are tied MAX(C) values) we order the A to get the minimum A to the top.
Seems like it is a greatest n per group problem:
WITH cte AS (
SELECT *, RANK() OVER (PARTITION BY B ORDER BY C DESC, A ASC) AS rnk
FROM t
)
SELECT *
FROM cte
WHERE rnk = 1
You're not clear which A needs to be considered, the above returns the row with smallest A.
itseems to me you need max()
select A,B, max(c) from table_name
group by A,B
this will work:
select * from (SELECT t.*,
rank() OVER (PARTITION BY A,B order by C) rank
FROM tablename t)
where rank=1 ;

SQL combining of a COUNT with a WHERE in single query

Here is the data, call it table T
A B
-- --
1 14
2 15
3 16
4 1
4 3
4 6
4 9
4 12
4 15
I would like to get the value of A that has only one value and a B value of 15.
There are two rows where B=15 but there are 6 rows where A=4 and only one row where A=2.
So the correct SQL should return me the 2.
I have tried this but it returns both rows.
select A from T group by A,B having Count(A) = 1 and B = 15
This similarly fails:
select A from T where B = 15 group by A having count( A ) = 1
Try this:
select A
from T
group by A
having Count(A) = 1 and Max(B) = 15;
Your problem seems to be that you are grouping by both columns. You only want to group by A.
Admittedly, your query has group by A, T, but I think that is a typo, based on the described behavior.
You can check the count of B after grouping by A.
select A
from T
group by A
having Count(B) = 1 and max(B) = 15

Assigning row number according to the Column value SQL Server?

I have a table like this in SQL server 2014:
name
a
a
b
b
b
c
d
d
d
I want to create another column that is S.No. , but serial number value will be assigned according to name column. If name occurs 2 times the value of s.no. will be 1 and 2.If d is 3 times than value for d will be 1,2 and 3 and than again counter will start with 1 for e. so the table will be like:
name S.no.
a 1
a 2
b 1
b 2
b 3
c 1
d 1
d 2
d 3
Any solution? thanks for the help.
Use ROW_NUMBER():
SELECT name, ROW_NUMBER() OVER (PARTITION BY name ORDER BY (SELECT 1)) [S.no.]
FROM T
Just in another way by using Count()
select
Name,
Count(1) over (partition by Name ORDER BY Name ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) as Slno
from MyTable

SQL count nulls and non nulls

Apologies if there is already an answer out there for this, I couldn't find it anywhere!
I want to create a SQL query (in Oracle) displays a list of all A, B, C rows, example below, where there are more than 1 counts of D, including Nulls.
Say I have 5 columns:
A B C D E
1 1 100 A 1
1 1 100 2
1 1 200 A 3
1 1 200 1
2 2 100 A 2
2 2 100 3
2 2 100 B 1
2 2 100 C 2
The blanks are null.
I want the following results back, ignoring E altogether:
A B C count
1 1 100 2
1 1 200 2
2 2 100 4
The problem I have currently is that if I use the following query, it doesn't count the nulls:
SELECT A, B, C, count(D)
FROM <TABLE>
GROUP BY A, B, C HAVING COUNT(D) > 1
I know that count(*) does take into account nulls but I have other columns in my table that I don't want to include in my query.
Simple COUNT(*)` should do it
SELECT A, B, C, COUNT(*) count
FROM table1
GROUP BY A, B, C
ORDER BY A, B, C
Output:
| A | B | C | COUNT |
-----------------------
| 1 | 1 | 100 | 2 |
| 1 | 1 | 200 | 2 |
| 2 | 2 | 100 | 4 |
Here is SQLFiddle demo
COUNT(*) just counts the rows therefore it doesn't care for NULLs. On the other hand when you specify the column it will count only rows with non-null values in that column.
What you're asking for is given by:
SELECT A, B, C, count(*)
FROM <TABLE>
GROUP BY A, B, C
HAVING COUNT(*) > 1
If what you want is for the count to be based on distinct values in D, then:
SELECT A, B, C, count(distinct coalesce(d,'!'))
FROM <TABLE>
GROUP BY A, B, C
HAVING count(distinct coalesce(d,'!')) > 1
Choose a value as the second argument of coalesce() that is never present in the table -- preferably one that a constraint prevents from existing.
If you just want a count, and be sure that it counts every row even if you have no column to count that is reliably not null, just use SUM(1) or COUNT(*)instead of count on the column;
SELECT A, B, C, SUM(1) dcount1, COUNT(*) dcount2
FROM Table1
GROUP BY A, B, C
HAVING SUM(1) > 1
This counts every row, no matter if any column is NULL.
An SQLfiddle to test with.