Increment Row_Number Only Where Distinct - tsql

I have the following table, which I've made very simple because I do not know how to format it as a table on here (side note if anyone could link me to an easy tutorial on that I would be forever grateful).
id
1
1
1
2
2
2
I'd like to add another column which increments in number only on distinct IDs so the outcome should be
Id
1
1
1
2
2
2
rowNum
1
1
1
2
2
2
Currently all I can manage to get is:
id
1
1
1
2
2
2
rowNum
1
2
3
4
5
6
I'm missing something very simple here as I'm confident I should be able to solve this issue using either row_number or rank and a window function but I cannot figure it out.

Use DENSE_RANK() instead of ROW_NUMBER():
SELECT
id,
DENSE_RANK() OVER (ORDER BY id) dr
FROM yourTable
Demo

You can do this with a subquery self join, as well.
mysql> select id,
> (select count(distinct id)
> from
> testtest b
> where b.id < a.id)
> from testtest a;
+------+---------------------------------------------------------------+
| id | (select count(distinct id) from testtest b where b.id < a.id) |
+------+---------------------------------------------------------------+
| 1 | 0 |
| 1 | 0 |
| 1 | 0 |
| 2 | 1 |
| 2 | 1 |
| 2 | 1 |
+------+---------------------------------------------------------------+
6 rows in set (0.01 sec)
And one more way:
select a.id, b.idRank
from testtest a,
(
select id,
rank() over
(order by id) as idRank
from (
select distinct id
from testtest
) testtest2
) b
where a.id = b.id

Related

how to drop rows if a variale is less than x, in sql

I have the following query code
query = """
with double_entry_book as (
SELECT to_address as address, value as value
FROM `bigquery-public-data.crypto_ethereum.traces`
WHERE to_address is not null
AND block_timestamp < '2022-01-01 00:00:00'
AND status = 1
AND (call_type not in ('delegatecall', 'callcode', 'staticcall') or call_type is null)
union all
-- credits
SELECT from_address as address, -value as value
FROM `bigquery-public-data.crypto_ethereum.traces`
WHERE from_address is not null
AND block_timestamp < '2022-01-01 00:00:00'
AND status = 1
AND (call_type not in ('delegatecall', 'callcode', 'staticcall') or call_type is null)
union all
)
SELECT address,
sum(value) / 1000000000000000000 as balance
from double_entry_book
group by address
order by balance desc
LIMIT 15000000
"""
In the last part, I want to drop rows where "balance" is less than, let's say, 0.02 and then group, order, etc. I imagine this should be a simple code. Any help will be appreciated!
We can delete on a CTE and use returning to get the id's of the rows being deleted, but they still exist until the transaction is comitted.
CREATE TABLE t (
id serial,
variale int);
insert into t (variale) values
(1),(2),(3),(4),(5);
✓
5 rows affected
with del as
(delete from t
where variale < 3
returning id)
select
t.id,
t.variale,
del.id ids_being_deleted
from t
left join del
on t.id = del.id;
id | variale | ids_being_deleted
-: | ------: | ----------------:
1 | 1 | 1
2 | 2 | 2
3 | 3 | null
4 | 4 | null
5 | 5 | null
select * from t;
id | variale
-: | ------:
3 | 3
4 | 4
5 | 5
db<>fiddle here

Get different LIMIT on each group on postgresql rank

To get 2 rows from each group I can use ROW_NUMBER() with condition <= 2 at last but my question is what If I want to get different limits on each group e.g 3 rows for section_id 1, 1 rows for 2 and 1 rows for 3?
Given the following table:
db=# SELECT * FROM xxx;
id | section_id | name
----+------------+------
1 | 1 | A
2 | 1 | B
3 | 1 | C
4 | 1 | D
5 | 2 | E
6 | 2 | F
7 | 3 | G
8 | 2 | H
(8 rows)
I get the first 2 rows (ordered by name) for each section_id, i.e. a result similar to:
id | section_id | name
----+------------+------
1 | 1 | A
2 | 1 | B
5 | 2 | E
6 | 2 | F
7 | 3 | G
(5 rows)
Current Query:
SELECT
*
FROM (
SELECT
ROW_NUMBER() OVER (PARTITION BY section_id ORDER BY name) AS r,
t.*
FROM
xxx t) x
WHERE
x.r <= 2;
Create a table to contain the section limits, then join. The big advantage being that as new sections are required or limits change maintenance is reduced to a single table update and comes at very little cost. See example.
select s.section_id, s.name
from (select section_id, name
, row_number() over (partition by section_id order by name) rn
from sections
) s
left join section_limits sl on (sl.section_id = s.section_id)
where
s.rn <= coalesce(sl.limit_to,2);
Just fix up your where clause:
with numbered as (
select row_number() over (partition by section_id
order by name) as r,
t.*
from xxx t
)
select *
from numbered
where (section_id = 1 and r <= 3)
or (section_id = 2 and r <= 1)
or (section_id = 3 and r <= 1);

Need to have subquery within subquery

I have a stock table which holds for example
Partnumber | Depot | flag_redundant
------------+-------+----------------
1 | 1 | 5
1 | 2 | 0
1 | 3 | 0
1 | 4 | 5
2 | 1 | 0
2 | 2 | 0
2 | 3 | 0
2 | 4 | 0
I need to be able to see the depots in which the parts have not been flagged as redundant, but the flag_redundant has been at least been flagged once for that part, and I need to ignore any parts where there has not been a flag flagged.
Any help appreciated!
I'm thinking of something along the lines of ....
SELECT stock.part, stock.depot,
OrderCount = (SELECT CASE WHEN Stock.flag_redundant = 5 THEN 1 end as Countcolumn FROM stock C)
FROM stock
Partnumber | MissingDepots
------------+---------------
1 | Yes
You can group by partnumber and set the conditions in the HAVING clause:
select
partnumber, 'Yes' MissingDepots
from stock
group by partnumber
having
sum(flag_redundant) > 0 and
sum(case when flag_redundant = 0 then 1 end) > 0
Or:
select
partnumber, 'Yes' MissingDepots
from stock
group by partnumber
having sum(case when flag_redundant = 0 then 1 end) between 1 and count(*) - 1
See the demo.
Results:
> partnumber | missingdepots
> ---------: | :------------
> 1 | Yes
Assuming you want to get these partnumbers that contain data sets with flag_redundant = 5 AND 0:
demo:db<>fiddle
SELECT
partnumber,
'Yes' AS missing
FROM (
SELECT
partnumber,
COUNT(flag_redundant) FILTER (WHERE flag_redundant = 5) AS cnt_redundant, -- 2
COUNT(*) AS cnt -- 3
FROM
stock
GROUP BY partnumber -- 1
) s
WHERE cnt_redundant > 0 -- 4
AND cnt_redundant < cnt -- 5
Group by partnumber
Count all records with flag_redundant = 5
Count all records
Find all partnumbers that contain any element with 5 ...
... and which have more records than 5-element records

Display all rows into two columns

I am having a View like this.
SemesterId Course Grade
1 course1 A
1 course2 B
1 course3 C
2 course4 D
2 course5 A
2 course6 B
2 course7 C
3 course8 D
3 course9 A
3 course10 B
4 course11 C
4 course12 D
I want to get result like below using postgre SQL.
SemesterId1 Course1 Grade1 SemesterId2 Course2 Grade2
1 course1 A 2 course4 D
1 course2 B 2 course5 A
1 course3 C 2 course6 B
2 course7 C
3 course8 D 4 course11 C
3 course9 A 4 course12 D
3 course10 B
How can I get this result?
This kind of tasks should be solved on client side. However, it's also an interesting issue to solve in SQL.
select
sid1, course1, grade1,
sid2, course2, grade2
from (
select
c1.semesterid sid1, c1.course course1, c1.grade grade1, c1.rk, c1.rn,
c2.semesterid sid2, c2.course course2, c2.grade grade2, c2.rk, c2.rn
from (
select *, dense_rank() over w rk, row_number() over w rn
from courses
where semesterid % 2 = 1
window w as (order by semesterid)
) c1
full join (
select *, dense_rank() over w rk, row_number() over w rn
from courses
where semesterid % 2 = 0
window w as (order by semesterid)
) c2
on c1.rk = c2.rk and c1.rn = c2.rn
order by coalesce(c1.rk, c2.rk), coalesce(c1.rn, c2.rn)
) sub
sid1 | course1 | grade1 | sid2 | course2 | grade2
------+----------+--------+------+----------+--------
1 | course1 | A | 2 | course4 | D
1 | course2 | B | 2 | course5 | A
1 | course3 | C | 2 | course6 | B
| | | 2 | course7 | C
3 | course8 | D | | |
3 | course9 | A | 4 | course11 | C
3 | course10 | B | 4 | course12 | D
(7 rows)
I don,t know why you do this this way, but you may use:
WITH tab_row_num AS (
SELECT row_number() over (PARTITION BY "SemesterId") rn, "SemesterId" , "Course" , "Grade" FROM table1
),
joint_tab AS (
select
t1_3."SemesterId" AS "SemesterId1", t1_3."Course" as "Course1" , t1_3."Grade" as "Grade1",
t2_4."SemesterId" AS "SemesterId2", t2_4."Course" as "Course2" , t2_4."Grade" as "Grade2"
from tab_row_num t1_3
full outer join tab_row_num t2_4
ON (t1_3."SemesterId" = 1 AND t2_4."SemesterId"=2 AND t1_3.rn=t2_4.rn)
OR (t1_3."SemesterId" = 3 AND t2_4."SemesterId"=4 AND t1_3.rn=t2_4.rn)
)
SELECT
COALESCE("SemesterId1"::TEXT, '') , COALESCE("Course1"::TEXT, '') , COALESCE("Grade1"::TEXT, ''),
COALESCE("SemesterId2"::TEXT, '') , COALESCE("Course2"::TEXT, '') , COALESCE("Grade2"::TEXT, '')
FROM (
SELECT *
FROM (
SELECT "SemesterId1" , "Course1" , "Grade1", "SemesterId2" , "Course2" , "Grade2"
FROM joint_tab t
WHERE (t."SemesterId1" = 1 OR t."SemesterId1" IS NULL) AND (t."SemesterId2" = 2 OR t."SemesterId2" IS NULL)
ORDER BY "SemesterId1" NULLS LAST, "Course1" ASC, "Grade1" ASC, "SemesterId2" NULLS LAST, "Course2" ASC, "Grade2" ASC
) sub1
UNION ALL
SELECT * FROM (
SELECT "SemesterId1" , "Course1" , "Grade1", "SemesterId2" , "Course2" , "Grade2"
FROM joint_tab t WHERE (t."SemesterId1" = 3 OR t."SemesterId1" IS NULL) AND (t."SemesterId2" = 4 OR t."SemesterId2" IS NULL)
ORDER BY "SemesterId1" NULLS LAST, "Course1" ASC, "Grade1" ASC, "SemesterId2" NULLS LAST, "Course2" ASC, "Grade2" ASC
) sub2
) sub

pl sql query recuresive looping

i have only one table "tbl_test"
Which have table filed given below
tbl_test table
trx_id | proj_num | parent_num|
1 | 14 | 0 |
2 | 14 | 1 |
3 | 14 | 2 |
4 | 14 | 0 |
5 | 14 | 3 |
6 | 15 | 0 |
Result i want is : when trx_id value 5 is fetched
it's a parent child relationship. so,
trx_id -> parent_num
5 -> 3
3 -> 2
2 -> 1
That means output value:
3
2
1
Getting all parent chain
Query i used :
SELECT * FROM (
WITH RECURSIVE tree_data(project_num, task_num, parent_task_num) AS(
SELECT project_num, task_num, parent_task_num
FROM tb_task
WHERE project_num = 14 and task_num = 5
UNION ALL
SELECT child.project_num, child.task_num, child.parent_task_num
FROM tree_data parent Join tb_task child
ON parent.task_num = child.task_num AND parent.task_num = child.parent_task_num
)
SELECT project_num, task_num, parent_task_num
FROM tree_data
) AS tree_list ;
Can anybody help me ?
There's no need to do this with pl/pgsql. You can do it straight in SQL. Consider:
WITH RECURSIVE my_tree AS (
SELECT trx_id as id, parent_id as parent, trx_id::text as path, 1 as level
FROM tbl_test
WHERE trx_id = 5 -- start value
UNION ALL
SELECT t.trx_id, t.parent_id, p.path || ',' || t.trx_id::text, p.level + 1
FROM my_tree p
JOIN tbl_text t ON t.trx_id = p.parent
)
select * from my_tree;
If you are using PostgresSQL, try using a WITH clause:
WITH regional_sales AS (
SELECT region, SUM(amount) AS total_sales
FROM orders
GROUP BY region
), top_regions AS (
SELECT region
FROM regional_sales
WHERE total_sales > (SELECT SUM(total_sales)/10 FROM regional_sales)
)
SELECT region,
product,
SUM(quantity) AS product_units,
SUM(amount) AS product_sales
FROM orders
WHERE region IN (SELECT region FROM top_regions)
GROUP BY region, product;