SQL Find following session - different logic than cross join - sql

I have a set of data that stores two types of sessions. It is mobile data usage versus wifi data usage.
ID Session_Type
1 Cell
2 WiFi
3 Cell
4 Cell
5 WiFi
.
.
.
.
1000 Cell
1001 WiFi
Desired Results
Cell_ID. Next_WiFi_sess_id
1 2
3 5
4 5
.
.
1000 1001
I have gotten to the extent of joining the table by itself and done such that an id is > than the wifi id, but I am sure if this is perfect solution. Can you do this in a Lag for better performance?
select a.id, b.id
from
table a
join table b
where a.id > min(b.id)

You can use window functions -- specifically, a cumulative minimum:
select t.*
from (select t.*,
min(case when session_type = 'WiFi' then id end) over (order by id rows between current row and unbounded following) as next_wifi_id
from t
) t
where session_type = 'Cell';

Here is one option that uses window functions: you can get the next WiFi session with a window min; the trick is to order the frame by descending id:
select id, next_wifi_id
from (
select t.*,
min(case when session_type = 'WiFi' then id end) over(order by id desc) next_wifi_id
from mytable t
) t
where session_type = 'Cell'
Demo on DB Fiddle - this is Postgres, but the behavior is the same in Hive.
id | next_wifi_id
-: | -----------:
1 | 2
3 | 5
4 | 5

Related

Finding Difficulty in getting maximum value

V_ABC(its a View)
ID value interest Reference Code
1 5 Fixed 2
1 2 Variable 4
2 6 Variable 5
2 2 Fixed 1
3 4 Fixed 5
3 1 Variable 4
i need this OutPut please.
ID value Interest Reference Code
1 7 Fixed 4
2 8 Variable 5
3 5 Fixed 5
I have a view V_ABC. I am trying to add value which is fine and also getting Max reference Code.
On Top, iIam trying to get interest type which based on maximum value but failed so far. e.g in view,
ID 1 has maximum value 5 and need Interest Fixed
ID 2 maximum value 6 and interest should be Variable
ID 3 maximum value 4 and interest should be fixed .
I am trying to get interest. Here is my SCRIPT. I am using SQL server 2016
Select id,sum(value),Max(ReferenceCode)
(
Select id,value,
first_value(Interest) over (Partition by value Order by value desc) as Interest,Referencecode From V_ABC
)dd
group by id
Probably the simplest method uses row_number() and conditional aggregation:
select id, sum(value),
max(case when seqnum = 1 then interest end),
max(case when seqnum = 1 then reference_code end)
from (select t.*,
row_number() over (partition by id order by value desc) as seqnum
from t
) t
group by id;
If you want to be fancy, you can use select distinct with window functions:
select distinct id,
sum(value) over (partition by id),
first_value(interest) over (partition by id order by value desc),
first_value(reference_code) over (partition by id order by value desc)
from t;

sql - select single ID for each group with the lowest value

Consider the following table:
ID GroupId Rank
1 1 1
2 1 2
3 1 1
4 2 10
5 2 1
6 3 1
7 4 5
I need an sql (for MS-SQL) select query selecting a single Id for each group with the lowest rank. Each group needs to only return a single ID, even if there are two with the same rank (as 1 and 2 do in the above table). I've tried to select the min value, but the requirement that only one be returned, and the value to be returned is the ID column, is throwing me.
Does anyone know how to do this?
Use row_number():
select t.*
from (select t.*,
row_number() over (partition by groupid order by rank) as seqnum
from t
) t
where seqnum = 1;

Merging multiple rows into one using Postgresql

I am trying to combine multiple rows with the same IDs to one.
My raw table looks like this:
ID | person_id | eur_amount
1 3 200
1 2 100
2 3 80
2 2 100
The output should look like this:
ID | person_1 | eur_amount_1 | person_2 | eur_amount_2 |
1 3 200 2 100
2 3 80 2 100
The max number of persons is the same. I already tried solving it with a multiple JOIN statements and the crosstab() function as mentioned here PostgreSQL Crosstab Query.
But I couldn't find a solution for this - does anyone know a good way to achive the desired output?
Thanks in advance!
You can do this using cross tab or conditional aggregation. But you need to identify the rows, using row_number(). For instance:
select id,
max(case when seqnum = 1 then person_id end) as person_id_1,
max(case when seqnum = 1 then eur_amount end) as eur_amount_1,
max(case when seqnum = 2 then person_id end) as person_id_2,
max(case when seqnum = 2 then eur_amount end) as eur_amount_2
from (select t.*,
row_number() over (partition by id order by id) as seqnum
from t
) t
group by id;

SELECT Distinct with condition of other column value

I have the schema built at this SQL Fiddle if you want to try out.
I have the following data
AutoID Apartment Flag Description
====== ========= ==== ===========
1 1 NO Device 1
2 1 NO Device 2
3 1 NO Device 3
4 2 NO Device 4
5 2 NO Device 5
6 3 NO Device 6
7 3 NO Device 7
8 3 YES Device 8
9 3 NO Device 9
I'm trying to get the data with the following rule
Only select distinct Apartment value
IF Flag is YES then select that item for the distinct value
So if I run the SQL statement I would end up with
AutoID Apartment Flag Description
====== ========= ==== ===========
1 1 NO Device 1
4 2 NO Device 4
8 3 YES Device 8
I've been trying to play around with OVER() and PARTITION BY with little luck. Any help or guidance is greatly appreciated.
;WITH CTE AS
(
SELECT *,
RN = ROW_NUMBER() OVER(PARTITION BY Apartment
ORDER BY CASE WHEN [Flag] = 'YES' THEN 1 ELSE 2 END,
[AutoID])
FROM TableA
)
SELECT *
FROM CTE
WHERE RN = 1
Here is the modified sqlfiddle
First step - assign order numbers in each group with the same apartment number
Second step - select only the first one
select AutoID, Apartment, Flag, Description from (
select AutoID, Apartment, Flag, Description, row_number() over (partition by apartment order by Flag desc) rnum
from table1)
where rnum = 1

Running Totals again. No over clause, no cursor, but increasing order

I am still having trouble creating an running total based on the increasing order of the value. Row id has no real meaning, it is just the PK. My server doesn't support OVER.
Row Value
1 3
2 7
3 1
4 2
Result:
Row Value
3 1
4 3
1 6
2 13
I have tried self and cross joins where I specify that the value of the second amount(the one being summed up) is less than the current value of the first. I have also tried doing this with the having clause but that always threw an error when I tried it that way. Can someone explain why it would be wrong to use it in that manner and how I should be doing it?
Here is one way to do a running total:
select row, value,
(select sum(value) from t t2 where t2.value <= t.value) as runningTotal
from t
you can use the with rollup command if you have sql server 2008.
select sum(value) from t t2 where t2.value <= t.value with rollup
If your platform supports recursive queries(IIRC you should omit the RECURSIVE keyword for microsoft stuff). Because the CTE needs to estimate the begin/end of a "chain", unfortunately, the tuples need to be ordered in some way (I use the "row" field; an internal tuple-id would be perfect for this purpose):
WITH RECURSIVE sums AS (
-- Terminal part
SELECT d0.row
, d0.value AS value
, d0.value AS runsum
FROM data d0
WHERE NOT EXISTS (
SELECT * FROM data nx
WHERE nx.row < d0.row
)
UNION
-- Recursive part
SELECT t1.row AS row
, t1.value AS value
, t0.runsum + t1.value AS runsum
FROM data t1
, sums t0
WHERE t1.row > t0.row
AND NOT EXISTS (
SELECT * FROM data nx
WHERE nx.row > t0.row
AND nx.row < t1.row
)
)
SELECT * FROM sums
;
RESULT:
row | value | runsum
-----+-------+--------
1 | 3 | 3
2 | 7 | 10
3 | 1 | 11
4 | 2 | 13
(4 rows)