Rows to comma separated list in SQL - sql

I have a requirement wherein the table structure I have looks like
ID Owner Id NAME
1 20 Name 1
1 21 Name 2
1 34 Name 3
2 10 Name 4
2 12 Name 5
3 100 Name 6
I need a query that would give me the results as
ID Owner ID Name
1 20 Name 1, Name2, Name 3
2 10 Name4, Name5
3 100 Name 6
Currently we do this on the codebehind, but I would ideally like to do this through SQL and see if that amounts to any performance improvement.

You did not mention your DBMS so I'm assuming PostgreSQL:
SELECT id,
min(owner_id) as lowest_id,
string_agg(name, ', ') as name_list
FROM the_table
GROUP BY id

Related

Condition filtering SQL

I have a table
Table name - commands
id
name
status
group_id
id - number
name - string
status - 0 or 1
group_id - number
I need to sort as follows: for all elements with the same group_id I have to check if at least one has a status of 1, if so, then leave, if not, then remove such a group and so on for all group_id
I tried to do it through GROUP BY, and then using HAVING to remove unnecessary groups, but this way I don't get the whole table to be displayed or a query that does not work.
I think it should look like:
SELECT COUNT(*) FROM commands GROUP BY group_id HAVING *condition*
Please let me know if there are any other commands to use.
id
name
status
group_id
1
name1
0
1
2
name2
0
1
3
name3
0
2
4
name4
1
2
5
name5
1
2
6
name6
0
3
7
name7
1
4
Result:
id
name
status
group_id
3
name3
0
2
4
name4
1
2
5
name5
1
2
7
name7
1
4
In Postgres, that's a good spot to use a boolean window function:
select *
from (
select t.*, bool_or(status = 1) over(partition by group_id) has_status_1
from mytable t
) t
where has_status_1
bool_or checks if any row in the group satisfies its predicate ; we can use this information for filtering.
The upside is that the table is scanned only once, as opposed to the correlated subquery solution.
You may use EXISTS operator with a correlated subquery as the following:
SELECT id, name, status, group_id
FROM table_name T
WHERE EXISTS(SELECT 1 FROM table_name D WHERE D.group_id = T.group_id AND D.status=1)
ORDER BY id
See a demo.

How do I convert SQL data from one view to this other view in Postgres

I have table with data like this
id group order value
-------------------------
1 1 1 23
2 1 2 34
3 2 1 234
4 2 2 77
5 2 3 102
I want to insert into table so I have one row per group, with the value showing a string of comma-separated values orders based on the order.
id group value
----------------
1 1 23,34
2 2 234,77,102
How do I do this? I'm using Postgres 9.3
Postgres supports string_agg():
select row_number() over () as id, "group", string_agg(value, ',' order by "order")
from t
group by "group";
I would look at PostgreSQL's string_agg aggregate function.

Write nested SQL query

I have 2 tables
Table1
ID Name
--------------------
1 John Carter
2 Jack Hammer
3 John Adams
4 John Doe
5 Brian Adams
Table2
ID ID_FromTable1
-----------------------------
1 2
2 3
3 1
4 1
5 1
6 2
7 3
8 1
9 1
10 5
11 4
12 5
13 4
ID in both tables is the primary key
ID_FromTable1 is the foreign key pointing to ID of Table1.
Now I do something like this:
SELECT ID
FROM Table1
WHERE Name like '%John%'
This will give me the IDs 1, 3, 4.
Now using these IDs, I want to write a query on Table2 to delete all entries where ID_FromTable1 are 1, 3, 4.
Please help me write one single SQL query to get all the IDs from Table1 where Name is 'John' and then using those IDs to delete entries from Table2.
I hope I have made the question clear. Do let me know if you need any clarification.
You can use IN with subquery:
DELETE FROM Table2
WHERE ID_FromTable1 IN ( SELECT ID
FROM Table1
WHERE Name LIKE '%John%' )
In MySQL you can do it with this join
delete table2
from table2
join table1 on table2.id_fromtable1 = table1.id
WHERE t1.Name like '%John%'

How to apply Joins in Oracle to require result

I have Following 3 tables :
SHIFT_MASTER,PATTERN_MASTER,PATTERN_DETAILS
S_ID ,P_ID,P_D_ID are the priamry keys of SHIFT_MASTER,PATTERN_MASTER,PATTERN_DETAILS tables respectively.
SHIFT_MASTER
S_ID | S_NUMBER| S_Name
---------------------------------
1 A MORNING
2 B AFTERNOON
3 C NIGHT
PATTERN_MASTER
P_ID | P_NAME
----------------
1 Pattern 1
2 Pattern 2
PATTERN_DETAILS
P_D_ID|P_ID | S_ID| ...
---------------------
1 1 1
2 1 2
3 1 3
4 1 2
5 1 1
6 2 3
7 2 2
8 2 1
9 2 3
I GOT OUTPUT AS
P_ID | S_ID
1 1,2,3,2,1
2 3,2,1,3
USING QUERY
SELECT PATTERN_DETAILS.P_ID "PATTERN",
LISTAGG(PATTERN_DETAILS.S_ID, ', ')
WITHIN GROUP (ORDER BY PATTERN_DETAILS.P_D_ID) "SHIFT"
FROM PATTERN_DETAILS
GROUP BY PATTERN_DETAILS.P_ID;
WHAT I WANT IS
P_NAME | S_NUMBER
Pattern 1 A,B,C,B,A
Pattern 2 C,B,A,C
Any suggestion ??? Instead of P_ID i want to show pattern name and instead of shift id i want to show shift number .How to perform join operation along with listagg function ?
You need to join all three tables to get this,
SELECT pm.p_name "P_NAME",
listagg(sm.s_number, ', ') WITHIN GROUP (ORDER BY pd.p_d_id) "S_NUMBER"
FROM pattern_master pm,
pattern_details pd,
shift_master sm
WHERE sm.s_id= pd.s_id
AND pm.p_id = pd.p_id
GROUP BY pm.p_name;

Add auto incrementing number based on column

I am trying to wrap my head around a problem I hit exporting data from one system to another.
Let's say I have a table like:
id | item_num
1 1
2 1
3 2
4 3
5 3
6 3
I need to add a column to the table and update it to contain an incrementing product_num field based on item. This would be the end result given the above table.
id | item_num | product_num
1 1 1
2 1 2
3 2 1
4 3 1
5 3 2
6 3 3
Any ideas on going about this?
Edit: This is being done in Access 2010 from one system to another (sql server source, custom/unknown ODBC driven destination)
Perhaps you could create a view in your SQL Server database and then select from that in Access to insert into your destination.
Possible solutions in SQL Server:
-- Use row_number() to get product_num in SQL Server 2005+:
select id
, item_num
, row_number() over (partition by item_num order by id) as product_num
from MyTable;
-- Use a correlated subquery to get product_num in many databases:
select t.id
, t.item_num
, (select count(*) from MyTable where item_num = t.item_num and id <= t.id) as product_num
from MyTable t;
Same result:
id item_num product_num
----------- ----------- --------------------
1 1 1
2 1 2
3 2 1
4 3 1
5 3 2
6 3 3