get number of times values on the basis of input value - sql

Input table
Col
1
2
2
3
3
4
5
Output
1
2
2
2
2
3
3
3
3
3
3
4
4
4
4
5
5
5
5
5
Is there any way this could be achieved in sql with and without writing any function ? Please take a note that, column can have duplicate values.

you didn't state your DBMS product, but in Postgres this can be done using `generate_series()
select t.col
from the_table t
cross join generate_series(1, t.col)
order by t.col

This is just a cross join to a numbers/tally table. You already have one in your source data, so you can simply use it as a distinct list:
select i.col
from input i
cross join (select distinct col as n from input) n
where n.n <= i.col
order by i.col

Here is a standard SQL recursive query for this:
with cte (num, cnt) as
(
select num, num from mytable
union all
select num, cnt - 1 from cte where cnt > 1
)
select num from cte order by num;

Related

SQL query to partition rows into groups where lag (difference between rows) is greater than some value

Suppose I have a table like
id
1
3
4
10
12
19
and I'd like to group the ids (in sorted order) into the same group if they differ by 5 or less, and a new group if they differ by 6 or more. So the output would be:
id
group
1
1
3
1
4
1
10
2
12
2
19
3
Is this possible in SQL? It will be a query in Trino, and I see they have commands like lag and partition. Has anyone made a query like this that can help out?
You can use a cte with lead:
with cte(id, l1) as (
select t.id, abs(coalesce(lead(t.id) over (order by t.id), 0) - t.id) < 6 from tbl t
)
select c.id, (select sum(c1.id < c.id and c1.l1 = 0) from cte c1) + 1 from cte c

Reorder the rows of a table according to the numbers of similar cells in a specific column using SQL

I have a table like this:
D
S
2
1
2
3
4
2
4
3
4
5
6
1
in which the code of symptoms(S) of three diseases(D) are shown. I want to rearrange this table (D-S) such that the diseases with more symptoms come up i.e. order it by decreasing the numbers of symptoms as below:
D
S
4
2
4
3
4
5
2
1
2
3
6
1
Can anyone help me to write a SQL code for it in SQL server?
I had tried to do this as the following but this doesn't work:
SELECT *
FROM (
select D, Count(S) cnt
from [D-S]
group by D
) Q
order by Q.cnt desc
select
D,
S
from
D-S
order by
count(*) over(partition by D) desc,
D,
S;
Two easy ways to approach this:
--==== Sample Data
DECLARE #t TABLE (D INT, S INT);
INSERT #t VALUES(2,1),(2,3),(4,2),(4,3),(4,5),(6,1);
--==== Using Window Function
SELECT t.D, t.S
FROM (SELECT t.*, Rnk = COUNT(*) OVER (PARTITION BY t.D) FROM #t AS t) AS t
ORDER BY t.Rnk DESC;
--==== Using standard GROUP BY
SELECT t.*
FROM #t AS t
JOIN
(
SELECT t2.D, Cnt = COUNT(*)
FROM #t AS t2
GROUP BY t2.D
) AS t2 ON t.D = t2.D
ORDER BY t2.Cnt DESC;
Results:
D S
----------- -----------
4 2
4 3
4 5
2 1
2 3
6 1

PSQL, adding a "step increasing" column

have this values in a table column select a from tab:
a
1
2
3
4
5
6
7
15
16
18
Using a variable=3, how can create column b starting with min(a) and with the following values:
a
b
1
1
2
1
3
1
4
4
5
4
6
4
7
7
15
15
17
15
18
18
something like: for each a (ordered) maintain the value at most for 3, otherwise reset.
Thanks,
AAWNSD
I think you want window functions and groups of three based on arithmetic on a:
select a,
min(a) over (partition by ceiling(a / 3.0)) as b
from tab;
Here is a db<>fiddle.
Hmmm . . . I realize that the above returns "16" for the last row rather than 18. My above interpretation may not be correct. You may be saying that you want groups -- once they start -- to never exceed the group starting value plus 2.
If so, one approach is a recursive CTE:
with recursive tt as (
select a, row_number() over (order by a) as seqnum
from tab
),
cte as (
select a, seqnum, a as grp
from tt
where seqnum = 1
union all
select tt.a, tt.seqnum,
(case when tt.a <= grp + 2 then grp else tt.a end)
from cte join
tt
on tt.seqnum = cte.seqnum + 1
)
select *
from cte;

SQL Join table to itself

I have a table where there are two columns like below.
value1 DerivedFrom
1 0
2 1
3 2
4 3
5 4
Basically, what it is saying is 1 was new, 2 was derived from 1, 3 was derived from 2 and so on.
I want the out put with 1 as the master key and 2,3,4 and 5 as children.
value1 DerivedFrom
1 0
1 1
1 2
1 3
1 4
Is it achiveble in SQL ? Thanks in advance
As mentioned in the comment, the simplest way is with an rCTE (recursive Common Table Expression):
--Sample Data
WITH YourTable AS(
SELECT *
FROM (VALUES(1,0),
(2,1),
(3,2),
(4,3),
(5,4))V(value1,DerivedFrom)),
--Solution
rCTE AS(
SELECT YT.value1 as rootValue,
YT.value1,
YT.DerivedFrom
FROM YourTable YT
WHERE YT.DerivedFrom = 0
UNION ALL
SELECT r.rootValue,
YT.value1,
YT.DerivedFrom
FROM YourTable YT
JOIN rCTE r ON YT.DerivedFrom = r.value1)
SELECT r.rootValue AS value1,
r.DerivedFrom
FROM rCTE r;

SQL get the closest two rows within duplicate rows

I have following table
ID Name Stage
1 A 1
1 B 2
1 C 3
1 A 4
1 N 5
1 B 6
1 J 7
1 C 8
1 D 9
1 E 10
I need output as below with parameters A and N need to select closest rows where difference between stage is smallest
ID Name Stage
1 A 4
1 N 5
I need to select rows where difference between stage is smallest
This query can make use of an index on (name, stage) efficiently:
WITH cte AS (
SELECT TOP 1
a.id AS a_id, a.name AS a_name, a.stage AS a_stage
, n.id AS n_id, n.name AS n_name, n.stage AS n_stage
FROM tbl a
CROSS APPLY (
SELECT TOP 1 *, stage - a.stage AS diff
FROM tbl
WHERE name = 'N'
AND stage >= a.stage
ORDER BY stage
UNION ALL
SELECT TOP 1 *, a.stage - stage AS diff
FROM tbl
WHERE name = 'N'
AND stage < a.stage
ORDER BY stage DESC
) n
WHERE a.name = 'A'
ORDER BY diff
)
SELECT a_id AS id, a_name AS name, a_stage AS stage FROM cte
UNION ALL
SELECT n_id, n_name, n_stage FROM cte;
SQL Server uses CROSS APPLY in place of standard-SQL LATERAL.
In case of ties (equal difference) the winner is arbitrary, unless you add more ORDER BY expressions as tiebreaker.
dbfiddle here
This solution works, if u know the minimum difference is always 1
SELECT *
FROM myTable as a
CROSS JOIN myTable as b
where a.stage-b.stage=1;
a.ID a.Name a.Stage b.ID b.Name b.Stage
1 A 4 1 N 5
Or simpler if u don't know the minimum
SELECT *
FROM myTable as a
CROSS JOIN myTable as b
where a.stage-b.stage in (SELECT min (a.stage-b.stage)
FROM myTable as a
CROSS JOIN myTable as b)