Detect range and count from a table - sql

A table with 2 columns ordered by group, number:
group_id | number
---------+--------
1 | 101
1 | 102
1 | 103
1 | 106
2 | 104
2 | 105
2 | 107
What SQL query should I write to get the following output:
group_id | number_from | number_to | total
---------+-------------+------------+-------
1 | 101 | 103 | 3
1 | 106 | 106 | 1
2 | 104 | 105 | 2
2 | 107 | 107 | 1

Here is SQL Fiddel Demo
Below is the script
create table Temp(A int,B int);
insert into temp values (1,101);
insert into temp values (1,102);
insert into temp values (1,103);
insert into temp values (1,106);
insert into temp values (2,104);
insert into temp values (2,105);
insert into temp values (2,107);
Select T2.A "group_id",
Min(T2.B) "number_from",
Max(T2.B) "number_to",
Max(T2.E) "total"
from
(
select *,(B-C) D,
rank() over
(PARTITION by T.A,(B-C) order by T.A,T.B) E,
rank() over
(order by T.A,(B-C)) F
from
(select A,B,row_number()
over (order by (select 0)) C
from temp) T
) T2
group by T2.A,T2.D,T2.F
order by 1,2

i used this as example table:
create table temp (id int, val int)
insert into temp values (1,101),(1,102),(2,102),(2,104),(2,107)
insert into temp values (2,103)
insert into temp values (2,105)
insert into temp values (2,108)
insert into temp values (2,110)
this is what you want:
select t1id,cnt, min(t1val) as min, max(t1val), count(t1val)
from (
select tt1.*,
(select count (*) from
(
select t1.id as t1id,
t1.val as t1val,
(select val from temp t2 where t1.id = t2.id and t2.val = t1.val+1 ) as t2val,
row_number() over (order by t1.id, t1.val ) as rn
from temp t1
) tt2
where tt2.t2val is null and tt2.rn < tt1.rn
) cnt
from (
select t1.id as t1id,
t1.val as t1val,
(select val from temp t2 where t1.id = t2.id and t2.val = t1.val+1 ) as t2val,
row_number() over (order by t1.id, t1.val ) as rn
from temp t1
) tt1
)ttt1
group by t1id, cnt
order by t1id, min
update: fixed bug if table is unsorted)

WITH RECURSIVE rope AS (
SELECT i1.id AS low
, i1.id AS high
, i1.grp AS grp
, 1::integer AS cnt
FROM islands i1
-- no left neighbor
WHERE NOT EXISTS ( SELECT * FROM islands x WHERE x.grp = i1.grp AND x.id = i1.id-1)
UNION ALL
SELECT ch.low AS low
, i2.id AS high
, i2.grp AS grp
, 1+ch.cnt AS cnt
FROM islands i2
-- connect to left neighbor
JOIN rope ch ON i2.grp = ch.grp AND i2.id = ch.high+1
)
SELECT * FROM rope r
-- suppress subchains
WHERE NOT EXISTS (
SELECT * FROM rope nx
WHERE nx.low = r.low AND nx.cnt > r.cnt
)
;

Related

Left join from 2 tables with same ID

I have tabl1e1 and table2 with data
table1
location costA
a 5
a 10
a 15
b 11
b 12
table2
Location CostB
a 100
b 100
My goal to get the result
location costA costB
a 5 100
a 10
a 15
b 11 50
b 12
My query
select T1.location, T1.cost
from (
select location, cost
, row_number() over ( partition by location order by cost) rownumber
from table1
) T1 left join (
select location, cost
, row_number() over ( partition by location order by cost ) rownumber
from table2
) T2 on T2.location = T2.cost and T1.rownumber = T2.rownumber
I got
location costA missing costB column
a 5
a 10
a 15
b 11
b 12
Not sure why but can you point out the missing one. Thank you.
First of all you are expecting three columuns in result and your select statement contains only 2.
select T1.Location, T1.Cost
2nd the join should be
T2 on T1.[location] = T2.[location] and T1.rownumber = T2.rownumber
Below is the complete working example
DECLARE #table1 as table
(
[location] char,
costA int
)
DECLARE #table2 as table
(
[location] char,
costB int
)
INSERT INTO #table1
VALUES
('a', 5)
,('a', 10)
,('a', 15)
,('b', 11)
,('b', 12)
INSERT INTO #table2
VALUES
('a', 100)
,('b', 100)
select T1.[location], T1.costA, T2.costB
from (
select [location], costA
, row_number() over ( partition by location order by costA) rownumber
from #table1
) T1 left join (
select [location], costB
, row_number() over ( partition by location order by costB ) rownumber
from #table2
) T2 on T1.[location] = T2.[location] and T1.rownumber = T2.rownumber
The join
T2 on T2.location = T2.cost and T1.rownumber = T2.rownumber
should be on
T2 on T1.location = T2.location and T1.rownumber = T2.rownumber
select
T1.location,
T1.costA,
T2.costB
from (
select
location,
costA,
row_number() over ( partition by location order by costA) rownumber
from table1
) T1
left join (
select
location,
costB,
row_number() over ( partition by location order by costB ) rownumber
from table2
) T2
on T1.location = T2.location and T1.rownumber = T2.rownumber
GO
location | costA | costB
:------- | ----: | ----:
a | 5 | 100
a | 10 | null
a | 15 | null
b | 11 | 100
b | 12 | null
db<>fiddle here

Count of Table1_IDs in Table2_arrays

I'm working with two tables:
CREATE TABLE Table1
(
id int,
name varchar
)
CREATE TABLE Table2
(
id int,
name varchar,
link array<int>
)
Table2.link contains values that correspond to Table1.id. I'd like to count how many times each Table1.id appears in an instance of Table2.link. This would be trivial using cell references in Excel, but I can't figure out how to do it with a SQL query.
Presto
select *
from (select l.id
,count(*) as cnt
from Table2 cross join unnest (link) as l(id)
group by l.id
) t2
where t2.id in (select id from Table1)
order by id
presto:default> select *
-> from (select l.id
-> ,count(*) as cnt
-> from Table2 cross join unnest (link) as l(id)
-> group by l.id
-> ) t2
-> where t2.id in (select id from Table1)
-> order by id;
id | cnt
----+-----
1 | 7
2 | 5
3 | 4
(3 rows)
PostgreSQL demo
create table Table1 (id int);
create table Table2 (arr int[]);
insert into Table1 values
(1),(2),(3)
;
insert into Table2 values
(array[1,5]),(array[1,3]),(array[1,2,3]),(array[2,3])
,(array[1,2,4]),(array[1,2]),(array[1,3,5]),(array[1,2,4])
;
select *
from (select unnest(arr) as id
,count(*) as cnt
from Table2
group by id
) t2
where t2.id in (select id from Table1)
order by id
+----+-----+
| id | cnt |
+----+-----+
| 1 | 7 |
+----+-----+
| 2 | 5 |
+----+-----+
| 3 | 4 |
+----+-----+

TSQL Distinct Counts

I have a table that looks like this:
ID SuppressionTypeID PersonID
------------------------------
1 1 123
2 1 456
3 2 456
I want to get a rolling count (distinct people) rather than a normal group by count.
e.g. not this:
SuppressionTypeID Count
---------------------------
1 2
2 1
This:
SuppressionTypeID RecordsLost
----------------------------------
1 2
2 0
The latter being zero as we lost person 456 on suppresiontypeid 1.
Thanks in advance.
You may need to use a temporary table or a table variable as shown below
DECLARE #t TABLE (
ID INT
,SuppressionTypeID INT
,PersonID INT
)
INSERT INTO #t
SELECT 1
,1
,123
UNION ALL
SELECT 2
,1
,456
UNION ALL
SELECT 3
,2
,456
DECLARE #t1 TABLE (
ID INT
,SuppressionTypeID INT
,PersonID INT
,firstid INT
)
INSERT INTO #t1
SELECT *
,NULL
FROM #t
UPDATE t1
SET t1.firstid = t2.firstid
FROM #t1 AS t1
INNER JOIN (
SELECT personid
,min(SuppressionTypeID) AS firstid
FROM #t1
GROUP BY personid
) AS t2 ON t1.PersonID = t2.PersonID
SELECT coalesce(t2.firstid, t1.SuppressionTypeID) AS SuppressionTypeID
,count(DISTINCT t2.personid) AS count
FROM #t1 AS t1
LEFT JOIN #t1 AS t2 ON t1.personid = t2.personid
AND t1.SuppressionTypeID = t2.firstid
GROUP BY coalesce(t2.firstid, t1.SuppressionTypeID)
The result is
SuppressionTypeID count
----------------- -----------
1 2
2 0
You can try;
with tmp_tbl as (
select
x.SuppressionTypeID, count(x.PersonID) as RecordsLost
from (
select
min(SuppressionTypeID) as SuppressionTypeID,
PersonID
from tbl
group by PersonID
) as x
group by x.PersonID
order by x.SuppressionTypeID
)
select
distict t.SuppressionTypeID, coalesce(tmp.RecordsLost, 0) as RecordsLost
from tbl t
left join tmp_tbl tmp on tmp.SuppressionTypeID = t.SuppressionTypeID

Get groups that are exactly equal to a table

I have a query that groups easily. I need to get the groups that have exactly the same records to another table (relationship).
I'm using ANSI-SQL under SQL Server, but I accept an answer of any implementation.
For example:
Table1:
Id | Value
---+------
1 | 1
1 | 2
1 | 3
2 | 4
3 | 2
4 | 3
Table2:
Value | ...
------+------
1 | ...
2 | ...
3 | ...
In my example, the result is:
Id |
---+
1 |
How imagined that it could be the code:
SELECT Table1.Id
FROM Table1
GROUP BY Table1.Id
HAVING ...? -- The group that has exactly the same elements of Table2
Thanks in advance!
You can try the following:
select t1.Id
from Table2 t2
join Table1 t1 on t1.value = t2.value
group by t1.Id
having count(distinct t1.value) = (select count(*) from Table2)
SQLFiddle
To get the same sets use an inner join:
SELECT Table1.Id
FROM Table1
INNER JOIN table2 ON table1.id=table2.id
GROUP BY Table1.Id
HAVING ...? --
CREATE TABLE #T1 (ID INT , [Values] INT) INSERT INTO #T1 VALUES (1,1),(1,2),(1,3),(2,4),(2,5),(3,6)
CREATE TABLE #T2 ([Values] INT) INSERT INTO #T2 VALUES (1),(2),(3),(4)
SELECT * FROM #T1
SELECT * FROM #T2
SELECT A.ID
FROM
( SELECT ID , COUNT(DISTINCT [Values]) AS Count FROM #T1
GROUP BY ID
) A
JOIN
(
SELECT T1.ID, COUNT(DISTINCT T2.[Values]) Count
FROM #T1 T1
JOIN #t2 T2
ON T1.[Values] = T2.[Values]
GROUP BY T1.ID
) B
ON A.ID = B.ID AND A.Count = B.Count

Insert data into temp table from 2 source tables

I have 2 SELECT statements that both return 13 rows from dirrefernt tables
I would like to create 1 temporary table with 2 columns and insert the 2 result rows into the 2 columns. Is there a way to do this?
So
1 - SELECT INPOS FROM TABLE1 returns
1,2,3,4,5,6,7,18,9,10,11,12,13
2 - SELECT CODE FROM TABLE2 returns
CODEA,CODEB,CODEC,CODED,CODEE,CODEF,CODEG,CODEH,CODEI,CODEJ,CODEK,CODEL,CODEM
I would like my temporary table to be
1 | CODEA
2 | CODEB
3 | CODEC
4 | CODED
5 | CODEE
6 | CODEF
7 | CODEG
8 | CODEH
9 | CODEI
10 | CODEJ
11 | CODEK
12 | CODEL
13 | CODEM
Try this:
WITH T1 AS (
SELECT ROW_NUMBER() OVER(ORDER BY INPOS) ID, INPOS FROM TABLE1
),
WITH T2 AS
(
SELECT ROW_NUMBER() OVER(ORDER BY CODE) ID, CODE FROM TABLE2
),
SELECT T1.INPOS, T2.CODE
FROM T1 INNER JOIN T2 ON T1.ID = T2.ID
Try something like this:
SELECT a.impos, b.code
FROM (
(
SELECT impos, RANK() OVER (ORDER BY impos ASC) AS link
FROM table1
) AS a INNER JOIN (
SELECT code, RANK() OVER (ORDER BY code ASC) AS link
FROM table2
) AS b ON a.link = b.link
)
sqlfiddle demo