Comma Separated list of rows of a column with group by on other columns - sql

Below is the structure of table I have: -
Table T1
C1 C2 C3
----------
X P A
X P B
Y Q C
Y Q D
Desired output: -
C1 C2 C3
------------
X P A,B
Y Q C,D
Note: - I know i can do the same with For XML('') with group by on C1 and C2, but the main problem in my case is that the table T1 here must be a physical table object (either permanent or temp or table var or CTE) in DB. But in my case it's a derived table and when i am using the below query it's saying invalid object.
In my case it's not good to replace the derived table with temp# tables or fixed tables or even with CTE or table variable because it will take a great effort.
SELECT
b.C1, b.C2, Stuff((',' + a.C3 from t1 a where a.c1 = b.c1 for XML PATH('')),1,1,'') FROM
T1 b group by b.c1,b.c2
I did not have T1 as fixed table. Please consider it as derived table only.
I need the solution with existing derived table.
Please help.
Below is the query with derived table: -
Please consider this only as a demo query. It's not as simple as given below and a lot of calculations have done to get the derived tables and 4 levels of derived tables have been used.
SELECT C1, C2, Stuff((',' + a.C3 from A B where a.c1 = b.c1 for XML PATH('')),1,1,'')
FROM
(
SELECT C1, C2, C3 FROM T1 WHERE C1 IS NOT NULL--and a lot of calculation also
)A
Please mind that T1 is not just below one step, in my case T1 the actual physical table is 4 level downs by derived tables.

If you can post the query the produces derived table, we can help you work it out, but as of the moment try substituting table1 with the derived query.
;WITH Table1
AS
(
SELECT C1, C2, C3 FROM T1 WHERE C1 IS NOT NULL--and a lot of calculation also
)
SELECT
C1,C2,
STUFF(
(SELECT ',' + C3
FROM Table1
WHERE C1 = a.C1 AND C2 = a.C2
FOR XML PATH (''))
, 1, 1, '') AS NamesList
FROM Table1 AS a
GROUP BY C1,C2
SQLFiddle Demo

Related

Return differing rows in tsql

I apologize for the basic non specific title. I can’t conceptualize how to ask this question or write the query I need in tsql. Any suggestions or guidance would be helpful. I have four columns that matter to me in a table:
c1(primarykey), c2, c3, c4
For any two rows, If c3 and c4 match but c2 doesn’t I want to return the rows. Amplify this to the entire table.
I’ve tried joining on a temp table then finding the difference through a left join on the table to itself but maybe I’m doing something incorrectly. Thank you in advance.
You could use:
WITH cte AS (
SELECT *, MIN(c2) OVER(PARTITION BY c3,c4) AS m, MAX(c2) OVER(PARTITION BY c3,c4) AS m2
FROM tab
)
SELECT *
FROM cte
WHERE m <> m2;
If you want to return the rows, then exists is a good way to go:
select t
from t
where exists (select 1
from t t2
where t2.c3 = t.c3 and t2.c4 = t.c4 and
t2.c2 <> t.c2
);
You do not mention NULL values in your question. If you have NULL values in any of the three columns, you would need to tweak the logic.
If you just wanted the c3/c4 pairs with different c2 values, you can use aggregation:
select c3, c4
from t
group by c3, c4
having min(c2) <> max(c2);
Finally, if you wanted to see pairs of non-matches on a single row, then:
select t.*, t2.c1, t2.c2
from t join
t t2
on t2.c3 = t.c3 and t2.c4 = t.c4 and
t2.c2 > t.c1;
With EXISTS:
select t.* from tablename t
where exists (
select 1 from tablename
where c2 <> t.c2 and c3 = t.c3 and c4 = t.c4
)
You can use Except
SELECT C1,C2,C3,C4 FROM TABLE1
EXCEPT
SELECT C4,C3,C2,C1 FROM TABLE1
This will check all the column values and if any of the value doesn't match then that record will be returns. More over you can add more columns to this query to match values.

How to create a select query that selects a repeating value in one of colums only once from multiple rows(example inside)

This is for example what I have(This is the result of a select query from different tables by different conditions let's call it Select X) :
ID c2 c3 c4
1 A de ys
2 A rq pm
3 B rq qs
I want a query that will give only one row with a certain value in c2, for example:
ID c2 c3 c4
1 A de ys
3 B rq qs
or
ID c2 c3 c4
2 A rq pm
3 B rq qs
I know how to do that using a data structure but it's more complicated, I wonder if there is a way to do that using a query?
Edit : This is what I tried and it gives error : " Syntax error in From clause "
( If it matters X = SELECT Responses.ID,Responses.PostID,Responses.Responding,Posts.ID,Posts.UserID,Users.ID,Users.Username FROM Responses,Posts,Users WHERE Responses.PostID =3 and Posts.ID = Responses.PostID AND Responses.Responding = Users.ID)
SELECT(Select X).*
FROM (Select X) as (Select X)
JOIN (
SELECT MIN(ID) AS ID, Users.ID
FROM (Select X)
GROUP BY Users.ID
) AS t2 ON (Select X).ID = t2.ID
EDIT : well I'll leave this open but at the end I chosen the data structure way not the query way.
Something like this:
SELECT t1.*
FROM mytable as t1
JOIN (
SELECT MIN(ID) AS ID, c2
FROM mytable
GROUP BY c2
) AS t2 ON t1.ID = t2.ID
This will pick the row having the minimum ID value within a group of same c2 values. You can use MAX aggregate function to get the second result set.
Note: I've made the assumption that ID is the PK of your table.
Edit:
You can use a derived table from you SELECT query like this:
SELECT t1.*
FROM (SELECT X ...) as t1
JOIN (
SELECT MIN(ID) AS ID, c2
FROM (SELECT X ...) AS t
GROUP BY c2
) AS t2 ON t1.ID = t2.ID

SQL: Reading description for a columns from a different table

I have a table (T1) with two columns (C1, C2) that describes the relationship between a parent group and child group. But this relation ship is defined based on group id. The name of the group is defined in another table (say T2).
Eg:
T1 has below values. C1 is for Parent Group Id and C2 is for Child Group Id. I have three groups in following order 1 - 2 - 3.
C1,C2
1,2
2,3
T2 has below values
C1,C2
1,Parent_Group
2,Child_Group1
3,Child_Group2
Now, I need to combine above table via SQL query, so that i will get below output.
C1,C2
Parent_Group,Child_Group1
Child_Group1,Child_Group2
How can i achieve the same?
Try this:
SELECT
C1.C2 AS C1, C2.C2 AS C2
FROM
T1 INNER JOIN
T2 C1 ON T1.C1 = C1.C1 INNER JOIN
T2 C2 ON T1.C2 = C2.C1

SQL assign value for join purpose to null field without update

With this sample data...
c1 c2 c3
10 a 10a
11 a **NULL**
12 a **NULL**
13 b 13b
13 b **NULL**
etc..
I want to assign c3 value to rows where it is NULL and c2 value is the same, but do not wish to actually update that value in table, only use it to join to another table while select runs.
I am able to do it using inner select and join, but I want to save as much processing power as possible because amount of data is huge and thought that some use of ISNULL or COALESCE should be able to do it, but I don't have enough experience to figure it on my own yet, or even say if it is possible. What do you think?
select
a.c1,
a.c2,
coalesce( a.c3, b.c3) as c3
from table1 a
left join table1 b
on a.c2 = b.c2
an a.c3 is null
and b.c3 is not null
this will work with the data that you have however if there is more than one row that is not null for c3 for a given c2 it will cause problems
If your DB supports max() over you can also do this
SELECT c1,
c2,
coalesce(c3, MAX(C3) over (partition by c2)) c3
from table1
demo
A sample pseudo code which i often use in my Query.
DECLARE #USER_ID AS VARCHAR(256)
SELECT #USER_ID = 'abc'
select *
from CC
INNER JOIN adm_co_users CR_US WITH(NOLOCK) ON ISNULL(CR_US.original_userID,'') =
(CASE ISNULL(CC.Createdby,'') WHEN '' THEN #USER_ID
ELSE CC.Createdby END )

Access SQL Query to search value in 2 tables but use just one?

I have 2 tables in MS Access and need to query them looking for a value. If the value is in A, then use that. If value is in B, then use that. If the value is in both tables, then use only the value from table A.
How can I make a query to do that?
Thanks!
How about:
SELECT IIF(IsNull(AField),(SELECT AField FROM Table2 WHERE ID=16), AField)
FROM Table1
WHERE ID=16
If you want to do an entire table rather than 1 row :-
select C1, C2 from TableA where C2 is not null
union all
select C1, C2 from TableB where C1 in ( select c1 from TableA where C2 is null )