case end / self-join postres sql - 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

Related

Explode a row into multiple rows based on a column value presto

I am looking to explode a row into multiple rows based on a column[integer] value, I am trying to do this using presto
Below is an example
id
count
1
5
2
2
expected output
id
count
1
5
1
5
1
5
1
5
1
5
2
2
2
2
in the above example, id 1 has to be repeated 5 times and id 2 has to be repeated 2 times based on the count.
Based on my experience, presto doesnt support recursive CTE.
Any help would be appreciated.
Thanks
You could make the count into array with REPEAT and then CROSS JOIN.
Your input:
CREATE TABLE test AS
SELECT id, count
FROM (
VALUES
(1, 5),
(2, 2)
) AS x (id, count)
Then:
SELECT id, t.count
FROM test
CROSS JOIN UNNEST(repeat(count, count)) AS t (count)
You don't need recursive CTE's here, you can use sequence or repeat to generate an array for corresponding length and then flatten it with unnest:
-- sample data
WITH dataset (id, count) AS (
VALUES (1, 5),
(2, 2)
)
-- query
select id, count
from dataset,
unnest (repeat(id, count)) as t (ignore)
-- unnest (sequence(0, count - 1)) as t (ignore)
Output:
id
count
1
5
1
5
1
5
1
5
1
5
2
2
2
2

What is the best way to initialize a SortOrder column (e.g. 0, 1, 2, 3) where there are multiple groups based on another field?

I have a table of list items. There is a ListID column used as an identifier to group the list items together. Is there a sane way to give every item a sort order, starting at 0 per list and incremental by one per item.
Basically, I need to populate the following SortOrder Column values for a large number of entries/ListIDs.
ID ListID SortOrder
1 1 0
2 0 0
3 1 1
4 0 1
5 1 2
6 0 2
7 2 0
8 2 1
9 2 2
You can use ROW_NUMBER() with a PARTITION on the ListId field for this:
Select Id, ListId,
Row_Number() Over (Partition By ListId Order By Id) -1 As SortOrder
From YourTable
Order By Id
I think you want:
WITH toupdate as (
SELECT t.*,
ROW_NUMBER() OVER (PARTITION BY ListId Order By id) as new_SortOrder
FROM tableName
)
UPDATE toupdate a
SET sortorder = new_sort_order;
SQL Server has the nice ability to update a subquery or CTE under some circumstances.
Do you need to persist the order of lists containing items that are shared between lists? If so, perhaps variations on this schema would work for you.
Item
id label
1 A
2 B
3 C
4 D
List
id listName
1 abc list
2 cbd list
3 aaa list
ListMembership
id listId itemId order
1 1 1 1
2 1 2 2
3 1 3 3
4 2 2 2
5 2 3 1
6 2 4 3
7 3 1 1
8 3 1 2
9 3 1 3
usage:
select i.label from listMembership as lm
join Item as i on i.id=lm.itemId
where lm.listId=2
order by lm.order
yields:
label
C
B
D

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

Order by followed by dependent order by

I have a table with part of data like below . I have done order by on edition_id .
Now there is further requirement of ordering laungauge_id which depends on value of edition_id.
Edition_id refers to city from which a newspaper is published.
Language_id refers to different languages in which newspaper is
published.
So suppose edition_id = 5 it means New Delhi.
For New Delhi language_id are 13(English ), 5 (Hindi) ,1(Telugu ),4(Urdu).
What i want is to display for New Delhi , is display all English articles first , followed by hindi , followed by Telugu followed by Urdu.
If edition_id=1 then order of language_id should be 13,1,2.
Similarly ,
If edition_id=5 then order of language_id should be 13,5,1,4
Right now what I have is
Edition_id | Language_id
1 1
1 2
1 13
1 1
1 13
1 2
5 4
5 1
5 1
5 4
5 13
5 5
5 13
What is required
Edition_id | Language_id
1 13
1 13
1 1
1 1
1 2
1 2
5 13
5 13
5 5
5 1
5 1
5 4
5 4
How to do this ? Please help.
Is something like this possibe
Select * from <table>
order by edition_id ,
case when edition=6 then <order specified for language_id ie 13,5,1,4>
I would create a supplementary ranking table. I would then JOIN to provide your sort order. Eg:
EDITION_SORT_ORDER
EDITION_ID LANGUAGE_ID RANK
---------- ----------- ----
1 13 1
1 1 2
1 2 3
5 13 1
5 5 2
5 1 3
5 4 4
Using this table in a query might look like this:
SELECT E.EDITION_ID, E.LANGUAGE_ID
FROM <TABLE> E LEFT OUTER JOIN EDITION_SORT_ORDER S ON
E.EDITION_ID = S.EDITION_ID AND
E.LANGUAGE_ID = S.LANGUAGE_ID
ORDER BY S.RANK
This way you can add other rules in future, and it isn't a huge mess of CASE logic.
Alternatively, if you want to avoid a JOIN, you could create a stored function which did a similar lookup and returned a rank (based on passed parameters of EDITION_ID and LANGUAGE_ID).
If you must use CASE, then I'd confine it to a function so you can re-use the logic elsewhere.
If there is no mathematical logic behind it, I would insert another column that can be used for proper sorting.
If you cannot do this, you can simply type out the rules for the relation like this:
Order By Edition_Id,
case Edition_id
when 1 then
case Language_id
when 13 then 1
when 1 then 2
when 2 then 3
end
when 5 then
case Language_id
when 13 then 1
when 5 then 2
when 1 then 3
when 4 then 4
end
end
without a fixed order colum you could things like that, but the logic is not comprehensible.
Assuming first criteria is length of Language_id,
Second is Edition_id= Language_id,
rest is order of Language_id it could or work this way:
Declare #t table(Edition_id int, Language_id int)
insert into #t values
(1, 1),
(1, 2),
(1, 13),
(1, 1),
(1, 13),
(1, 2),
(5, 4),
(5, 1),
(5, 1),
(5, 4),
(5, 13),
(5, 5),
(5, 13);
Select * from #t
order by Edition_id,Case when len (Cast(Language_ID as Varchar(10)))=1 then '1' else '0' end
+case when Edition_id=Language_id then '0' else '1' end
,Language_ID
You've probably considered this but if your desired ordering is always based of the actual alphabetical name of the language then there would usually be a table with the language description that you could join with and then sort by. I base this on your quote below.
...English articles first , followed by hindi , followed by Telugu
followed by Urdu.
SELECT E.EDITION_ID, E.LANGUAGE_ID, LN.LANGUAGE_NAME
FROM <TABLE> E LEFT OUTER JOIN <LANGUAGE_NAMES> LN ON
E.LANGUAGE_ID = LN.LANGUAGE_ID
ORDER BY 1, 3

SQL: Need to create two unique records for each single record

The simple question is how can you take a set of records with a PK and create exactly two records for each source with a slightly altered key for the duplicate? In other words, I take 4000 records and produce 8000 records where 4000 are identical and the other 4000 have a slightly altered key. I cannot do a union because this is essentially two selects (long story).
The rest gets complicated, but maybe necessary to provide examples.
This is my original set (it contains over 4000 records)
dateGroup areaGroup itemID editionID
1 1 1 1
1 1 1 2
1 2 1 1
1 2 2 1
2 1 1 1
2 1 1 2
2 2 1 1
2 2 1 2
For each record I need to create a duplicate record ganging the areaGroups together under '0', then create a comma separated list of original areaGroups as a separate field. (The "why" is some dumb programmer (me) made a mistake about 15 years ago.) I can renumber the editionIDs as necessary, but the original and duplicate record must have the same editionID (thus why a union wouldn't work). The PK remains the same as above (all fields)
dateGroup areaGroup itemID editionID aGroups
1 0 1 1 1
1 0 1 2 1
1 0 1 1 2 // Duplicate (EditionID)
1 0 2 1 2
2 0 1 1 1
2 0 1 2 1
2 0 1 1 2 // Duplicate (EditionID)
2 0 1 2 2
The end result would renumber the editionID as needed to make the record unique.
dateGroup areaGroup itemID editionID aGroups (EditionID is what is altered)
1 0 1 1 1
1 0 1 2 1
1 0 1 2 2 1 changed to 2 (one more than row 1)
1 0 2 1 2
2 0 1 1 1
2 0 1 2 1
2 0 1 2 2 1 changed to 2 (one more than row 1)
2 0 1 2 2
1 1 1 1
1 1 1 2
1 2 1 2 1 changed to 2 (editionID) to match
1 2 2 1
2 1 1 1
2 1 1 2
2 2 1 2 1 changed to 2 to match above
2 2 1 2
I know you could calculate the editionID like a row rank like so:
select row_number() over (
partition by dateGroup, itemID
order by dateGroup, itemID) as editionID
So all I need is to know how to duplicate the records from a single set
do a cross join on a derived table:
( select 1 as aGroups union all select 2 )
I'd create a temporary table with duplicates and their count.
Then I'd filter the original table to have only unique rows, and insert another row for each row in the temporary table, incrementing their editionID.
In MySQL, I'd use user #variables; not sure about MS SQL.
Did you try UNION ALL instead of just UNION
UDPATE perhaps I misunderstood the problem and I thought you were having a problem with the union loosing the duplicates.
If the problem is that you want to do a row_number over a union why don't you do somthing like
select row_number() over (
partition by dateGroup, itemID
order by dateGroup, itemID) as editionID
FROM
(
SELECT
dateGroup, itemID
FROM TableA
UNION ALL
SELECT
dateGroup, itemID
FROM TableB
) Data