I'm trying to achieve below result output - sql

can we get the below desired table by using PIVOT or something. I'm trying to convert below table to the desired output like below.
Data Set:
question_id element_id
1 john
1 bran
1 o_siera
2 brook
2 joseph
2 o_daniel
2 o_cody
3 derick
3 james
3 sophia
3 o_sandra
3 o_ashley
Desired Result:
question_id element_id element
1 john o_siera
1 bran o_siera
2 brook o_daniel
2 joseph o_daniel
3 derick o_sandra
3 james o_sandra
3 sophia o_sandra
OR
OR can we achieve it in this way
question_id element_id element
1 john o_siera
1 bran
2 brook o_daniel,o_cody
2 joseph
3 derick o_sandra, o_ashley
3 james
3 sophia

Its not an ideal data model. Something like this should work except when a value that begins with 'o_%' is an element_id and not an element.
This was not tested.
select t1.question_id
,case when t1.element_id not like 'o_%' then t1.element_id else '' end element_id
,case when t2.element_id like 'o_%' then t2.element_id else '' end element
from table t1
join table t2 on t1.question_id=t2.question_id

I would suggest:
select t.*, max_o
from (select t.*,
max(case when element_id like 'o\_%' then element_id end) over (partition by question_id) as max_o
from t
) t
where element_id not like 'o\_%';

Related

How to delete rows after the item which equals to exact value?

I have the following dataframe
Block_id step name
1 1 Marie
1 2 Bob
1 3 John
1 4 Lola
2 1 Alex
2 2 John
2 3 Kate
2 4 Herald
3 1 Alec
3 2 Paul
3 3 Rex
As you can see data frame is sorted by block_id and then by step. I want to delete only in one block_id everything after the row where I have name John(the row with John as well). So the desired output would be
Block_id step name
1 1 Marie
1 2 Bob
2 1 Alex
3 1 Alec
3 2 Paul
3 3 Rex
An updatable CTE with a cumulative conditional COUNT seems to be what you are after:
CREATE TABLE dbo.YourTable (BlockID int,
Step int,
[Name] varchar(10));
GO
INSERT INTO dbo.YourTable
VALUES(1,1,'Marie'),
(1,2,'Bob'),
(1,3,'John'),
(1,4,'Lola'),
(2,1,'Alex'),
(2,2,'John'),
(2,3,'Kate'),
(2,4,'Herald'),
(3,1,'Alec'),
(3,2,'Paul'),
(3,3,'Rex');
GO
WITH CTE AS(
SELECT COUNT(CASE [Name] WHEN 'John' THEN 1 END) OVER (PARTITION BY BlockID ORDER BY Step) AS Johns
FROM dbo.YourTable)
DELETE FROM CTE
WHERE Johns >= 1;
GO
SELECT *
FROM dbo.YourTable;
GO
DROP TABLE dbo.YourTable;
One method uses an updatable CTE:
with todelete as (
select t.*,
min(case when name = 'John' then step end) over (partition by block_id) as john_id
from t
)
delete from todelete
where id >= john_id;
Or, if you prefer, a correlated subquery:
delete from t
where id >= (select min(t2.id)
from t t2
where t2.blockid = t.blockid and t2.name = 'John'
);
For performance, both of these can take advantage of an index on (blockid, name, id).

Why does the cte return the error that it does not exist?

Here is my code
WITH CTE AS(
SELECT COUNT(CASE name WHEN 'John' THEN 1 END) OVER (PARTITION BY BlockID ORDER BY Step) AS Johns
FROM dbo.YourTable)
DELETE FROM CTE
WHERE Johns >= 1;
SELECT *
FROM dbo.YourTable;
It returns me the following error when I run the code in the notebook
ERROR: syntax error at or near "DELETE"
But I can't seem to find any mistake in the query
When I try to do it in online compiler it returns the error that relation "cte" does not exist
Maybe this errors can be related?...
Here what I'm trying to do with cte:
My first table:
Block_id step name
1 1 Marie
1 2 Bob
1 3 John
1 4 Lola
2 1 Alex
2 2 John
2 3 Kate
2 4 Herald
3 1 Alec
3 2 Paul
3 3 Rex
As you can see data frame is sorted by block_id and then by step. I want to delete only in one block_id everything after the row where I have name John(the row with John as well). So the desired output would be
Block_id step name
1 1 Marie
1 2 Bob
2 1 Alex
3 1 Alec
3 2 Paul
3 3 Rex
Create a CTE that returns for each Block_id the step of the first John.
Then join the table to the CTE:
WITH cte AS (
SELECT Block_id, MIN(step) step
FROM tablename
WHERE name = 'John'
GROUP BY Block_id
)
DELETE FROM tablename t
USING cte c
WHERE c.Block_id = t.Block_id AND c.step <= t.step
See the demo.

Oracle SQL - Display rows as columns - Many to Many Relationship

Good day! I need some guidance if I want to do is actually possible in Oracle SQL.
I have a table like this:
ID
Name
Code
999
Abby
1
999
Betty
1
999
Cass
2
999
Diane
2
999
Elly
2
999
Faye
3
999
Greg
4
999
Honey
4
999
Iman
4
999
Jam
4
999
Klade
5
And I want to achieve something like this:
ID
1
2
3
4
5
999
Abby
Cass
Faye
Greg
Klade
999
Betty
Dianne
Honey
999
Elly
Iman
999
Jam
`
I have tried joins, pivots, aggregates, but nothing seems to possibly work out (as far as I tried it.)
I even tried getting all the raw data and creating a new table but the only id I can reference them with is the ID.
Please help.
Any idea or references or resource to the right direction would be appreciated!
Thanks in advance!
Pivot is one option.
select *
from (select id, name, code,
row_number() over (partition by code order by name) rn
from test
)
pivot
(listagg(name, '') within group (order by null) val
for code in (1, 2, 3, 4, 5)
);
which results in
ID RN 1_VAL 2_VAL 3_VAL 4_VAL 5_VAL
---------- ---------- ---------- ---------- ---------- ---------- ----------
999 1 Abby Cass Faye Greg Klade
999 2 Betty Diane Honey
999 3 Elly Iman
999 4 Jam
The key idea is to use row_number(), but I prefer conditional aggregation:
select code,
max(case when code = 1 then name end) as code_1,
max(case when code = 2 then name end) as code_2,
max(case when code = 3 then name end) as code_3,
max(case when code = 4 then name end) as code_4,
max(case when code = 5 then name end) as code_5
from (select t.*,
row_number() over (partition by id, code order by name) as seqnum
from t
)
group by id, seqnum

Edit 2 rows into 2 columns in a single result SQL

I have the following table:
WorkID WorkDesc
--------------------
1 ABCD
2 DEFG
3 HIJK
then I've the following table as the detail of table one:
WorkDetailID WorkID WorkDetailDesc
-----------------------------------------
1 1 001
2 1 002
3 2 006
4 2 007
5 3 015
Each WorkID is always have maximum 2 records and minimum is 1.
I want to have the following result:
WorkID WorkDesc WorkDetailID1 WorkDetailID2
-------------------------------------------------------
1 ABCD 1 2
2 DEFG 3 4
3 HIJK 5 null
Does anyone have an idea how to do that?
Thank you.
You can use pivot. I prefer conditional aggregation. In either case, you need a column for the pivoting. row_number() to the rescue:
select t1.workid, t1.workdesc,
max(case when t2.seqnum = 1 then t2.workdetailid end) as workdetailid1,
max(case when t2.seqnum = 2 then t2.workdetailid end) as workdetailid2
from t1 join
(select t2.*,
row_number() over (partition by t2.workid order by t2.workdetailid) as seqnum
from t2
) t2
on t1.workid = t2.workid
group by t1.workid, t1.workdesc

postgresql statement prob

I have two table A and B as following.
A:
key type
0 t
1 f
2 t
3 f
4 t
5 t
.......
B:
key name
0 Mary
0 Tony
0 Krolik
1 Tom
2 Tony
3 Tony
3 Mary
3 Tom
4 Tony
4 Tim
5 Tim
5 Mary
5 Wuli
.....
I hope to find top n occurence name that it's type is 'f'.
For example, in A, the type of key 1 and 3 are 'f', we find key 1 and 3 in table B, there are 2 'Tom' and 1 'Mary' and 1 'Tony'.
1 Tom
3 Tony
3 Mary
3 Tom
if n = 1 and the table is just showed as before, we hope to get 'Tom', because its occurence is top 1.
How can I write sql statement to satisfy these requirement?
I write something like below, but it is wrong. Can anyone help me? I assume n = 20.
SELECT DISTINCT TOP 20 name
FROM B
WHERE key IN (
SELECT key
FROM A
WHERE "type" = 'f'
)
GROUP BY name
ORDER BY DESC;
You don't seem to need aggregation. And the equivalent of top in Postgres is limit or fetch first <row> rows:
SELECT name, key
FROM B
WHERE B.key IN (SELECT A.key
FROM A
WHERE "type" = 'f'
)
ORDER BY key;
This corresponds to the results presented in the question. Your description doesn't quite match those results.