Postgres Group and order by range (specific values) - sql

I have a table like this:
id simcard simcard_order
80769 56407503370245588410 1
80788 66329183922439284822 2
80803 20993658565113174305 0
80804 81781641934100313243 4
80852 71560493627263868232 3
80784 23739383536995189713 1
80793 42702512646659519628 2
80805 17990699721985463506 0
80832 08525531276567944345 4
80854 74478849586042090832 3
80786 22535328208807554315 1
80812 34317440773382930807 0
80826 36103390459816949722 2
80858 15439885499080289130 3
80862 26786481240939036248 4
80792 59566921916027957512 1
80813 98968026512101636608 0
80835 65834894114116066528 2
80864 17764015687751814947 4
80882 41427844162545991837 3
80887 41587969946566907740 4
80891 46059625228552654737 3
80824 76381392106884963712 1
80863 77385361462191701926 2
80868 46607630719285200008 0
80892 08860583551940471945 4
80899 85443153649210377733 3
80934 90908807112484733323 2
80937 25660906025678471304 0
80967 34298088103509862330 3
The column simcard_order has repeat values from 0 to 4.
I want to order the table like this:
id simcard simcard_order
80769 56407503370245588410 0
80788 66329183922439284822 1
80803 20993658565113174305 2
80804 81781641934100313243 3
80852 71560493627263868232 4
80784 23739383536995189713 0
80793 42702512646659519628 1
80805 17990699721985463506 2
80832 08525531276567944345 3
80854 74478849586042090832 4
80786 22535328208807554315 0
80812 34317440773382930807 1
80826 36103390459816949722 2
80858 15439885499080289130 3
80862 26786481240939036248 4
....
and so on... So in this case I have 3 groups of (0, 1, 2, 3, 4)
Always the order must be 0, 1, 2, 3, 4.
I have used this sql, but it does not work properly:
SELECT id, simcard, simcard_order
FROM tmp_pending_simcards
WHERE tmp_pending_simcards.simcard_order IN (0, 1, 2, 3, 4)
ORDER BY (0, 1, 2, 3, 4)

If I understand correctly:
SELECT id, simcard, simcard_order
FROM tmp_pending_simcards tps
WHERE tps.simcard_order IN (0, 1, 2, 3, 4)
ORDER BY ROW_NUMBER() OVER (PARTITION BY tps.simcard_order),
tps.simcard_order;
Usually, you would have an ORDER BY as part of ROW_NUMBER(), but Postgres does not require it.

Related

case end / self-join postres sql

I am trying to process data within the same table.
Input:
Table
id sort value
1 1 1
2 1 8
3 2 0
4 1 2
What I want to achieve is obtain for each id, the first encountered value for all value equal to its sort, and this ordered by id.
Output
Table
id sort value new
1 1 1 1
2 1 8 1
3 2 0 0
4 1 2 1
I tried to self join the table, but I constantly get relation not found. I tried with a case statement but I don't see how can I connect to the same table, I get the same error, relation not found.
The beauty of SQL is that many requirements (yours included) can be verbosely described in very similar way they are finally coded:
with t(id, sort, value ) as (values
(1, 1, 1),
(2, 1, 8),
(3, 2, 0),
(4, 1, 2)
)
select t.*
, first_value(value) over (partition by sort order by id) as "new"
from t
order by id
id
sort
value
new
1
1
1
1
2
1
8
1
3
2
0
0
4
1
2
1
fiddle

SQL From the same table find records shared by common criteria

DB: postgres (PostgreSQL) 10.16 (Ubuntu 10.16-0ubuntu0.18.04.1)
I have a table device_clients in which following data is present:
id
device_id
client_id
1
1
1
2
2
1
3
3
1
4
4
1
5
5
1
6
6
1
7
7
1
8
8
1
9
1
2
10
1
3
11
1
4
12
2
2
13
2
3
14
2
4
15
3
2
16
3
3
17
3
4
I need to find out devices common between each client I provide. For e.g. following are the devices for each client
Client-1 => 1, 2, 3, 4, 5, 6, 7, 8
Client-2 => 1, 2, 3
Client-3 => 1, 2, 3
Client-4 => 1, 2, 3
So for clients 1, 2, 3 the common devices expected are 1, 2, 3.
Can anybody please help me formulate an efficient query to achieve the desired results?
You can use aggregation. For instance:
select device_id
from t
where client_id in (1, 2, 3)
group by device_id
having count(*) = 3;
For convenience, you can pass the list of clients in as an array, allowing you to use:
select device_id
from t
where client_id = any(:client_ar)
group by device_id
having count(*) = cardinality(:client_ar)
You could join the table three times:
select a.device_id
from device_clients a
join device_clients b on b.device_id = a.device_id
join device_clients c on c.device_id = a.device_id
where a.client_id = 1
and b.client_id = 2
and c.client_id = 3

create a column that group values

To resume i want to put into the same group values that are associated:
Here is what i have :
col1 col2
1 2
1 3
2 3
4 5
5 6
and I want this :
col1 col2 group
1 2 1
1 3 1
2 3 1
4 5 2
5 6 2
To produce those two groups here are the steps if i do it manually.
row 1 : 1 is associated to 2 so they are on the same group let's call it group 1
row 2 : 1 is on group 1 and now 1 is associated to 3 so 3 is also on group 1
row 3 : 2 is on the group 1 and 3 is also on the group 1 so they are in the group 1
row 4 : 4 is not a value of the group 1 so i create a new group called 2 and i associate it with 5
row 5 : 5 has a group 2 and is associated to 6 so it has group 2.
Do you have an idea of to resolve this in SQL.
Knowing that i am using Hive or pyspark
Based on A.R.Ferguson answer i was able to figure out the solution using pyspark and graphframe:
from graphframes import *
vertices = sqlContext.createDataFrame([
("A", 1),
("B", 2),
("C", 3),
("D", 4),
("E", 5),
("F", 6)], ["name", "id"])
edges = sqlContext.createDataFrame([
(1, 2),
(1, 3),
(2, 3),
(4, 5),
(5, 6)], ["src", "dst"])
g = GraphFrame(vertices, edges)
result = g.connectedComponents()
result.show()
Thanks again Ferguson.

Select Query on Sql Server

The question may be very simple but i don't know how to fix it,
I have this table structure
sno left Right
1 2 1
2 2 2
3 1 2
4 3 1
5 2 4
6 7 1
7 2 8
How do I get a result set like the one below
sno left Right Result
1 2 1 1
2 2 2 2
3 1 2 1
4 3 1 1
5 2 4 2
6 7 1 1
7 2 8 2
I wanna select the Data what mimimum value is matched between two columns,
Eg:3 and 1
1 is minimum value between these two and 1 is matched with 3, so the matched value is 1.
eg: 2 and 4
2 is minimum value between these two and 2 is is mathed with 4, so the matched value is 2.
Edited:
If choose 8 and 2 for example
8 contains(1,2,3,4,5,6,7,8)
2 contains(1,2)
So the Result is 2
Because 2 values are matched here.
I hope i explained it well, thanks
The following SQL will return the positive value of a subtraction operation between the left and right values - in a column with Result as the header. It will calculate the difference between left and right values - ABS will make the result positive.
SELECT
sno,
left,
Right,
ABS(left - right) AS Result
FROM tablename
One of the possible solutions:
DECLARE #t TABLE ( sno INT, l INT, r INT )
INSERT INTO #t
VALUES ( 1, 2, 1 ),
( 2, 2, 2 ),
( 3, 1, 2 ),
( 4, 3, 1 ),
( 5, 2, 4 ),
( 6, 7, 1 ),
( 7, 2, 8 )
SELECT *,
(SELECT MIN(v) FROM (VALUES(l),(r)) m(v)) AS m
FROM #t
Output:
sno l r m
1 2 1 1
2 2 2 2
3 1 2 1
4 3 1 1
5 2 4 2
6 7 1 1
7 2 8 2
case
when left < right then left
else right
end

Getting a count from multiple columns with set values in SQL and MS Access

I have a table of information with multiple columns but each column can hold only 1 of 3 values (0,1,2). It is generated through user inputted choices of Yes, No Maybe. I want to count each column and be fed back the values.
EG Table:
ID Coffee Tea Water Hot_Choc
1 1 0 2 2
2 0 2 0 1
3 1 2 0 2
4 2 0 1 1
5 1 1 2 2
6 0 1 2 1
7 2 1 0 1
8 1 2 1 2
I'd like to query the data to an output like this:
Coffee Tea Water Hot_Choc
0 2 2 3 0
1 4 3 2 4
2 2 3 3 4
I tried running a basic count script:
SELECT coffee, count(*) FROM Drinks GROUP BY coffee
Which works fine.
and then tried evolving into:
SELECT coffee,tea,water,hot_choc, count(*) from Drinks group by coffee,tea,water,hot_choc
But with that I get a count for each instance. So when coffee is 0 what are the counts for tea, water and hot_choc.
I also tried with a sum(iif clause because I'm running in access:
select sum(iif(coffee=0,1,0)) as coffee_maybe,
sum(iif(coffee=1,1,0)) as coffee_no,
sum(iif(coffee=2,1,0)) as coffee_yes from drinks;
etc.
Which gets me this:
Coffee_maybe coffee_no coffee_yes tea_maybe tea_no tea_yes etc...
2 4 2 2 3 2
So I'm wondering if anyone has other thoughts as to how to get the count in the above format.
Thanks so much for the help, sorry it's been a long read I wanted to give as much context as possible.
I think the following will work in Access:
select 0, sum(iif(coffee = 0, 1, 0)) as coffee, sum(iif(tea = 0, 1, 0)) as tea,
sum(iif(water = 0, 1, 0)) as water, sum(iif(hot_choc = 0, 1, 0)) as hot_choc
from drinks d
union all
select 1, sum(iif(coffee = 1, 1, 0)) as coffee, sum(iif(tea = 1, 1, 0)) as tea,
sum(iif(water = 1, 1, 0)) as water, sum(iif(hot_choc = 1, 1, 0)) as hot_choc
from drinks d
union all
select 2, sum(iif(coffee = 2, 1, 0)) as coffee, sum(iif(tea = 2, 1, 0)) as tea,
sum(iif(water = 2, 1, 0)) as water, sum(iif(hot_choc = 2, 1, 0)) as hot_choc
from drinks d;
There are slightly easier ways to do this in other databases.