Comma-separated columns in SQL Server - sql-server-2008

I have a problem: I have two tables
Table1 which has two columns
Col1 Col2
---- ------
a value1
b value1
b value1
And Table2
Col1 Col2
---- ------
1 a,b
2 a,c
3 a,b,c
I want result
Col1 Col2
----- -----
a 1,2,3
b 1,3
c 2,3

WITH C AS
(
SELECT T2.Col1,
S.Item
FROM Table2 AS T2
CROSS APPLY dbo.SplitStrings(T2.Col2, ',') AS S
)
SELECT C1.Item AS Col1,
(
SELECT ','+CAST(C2.Col1 AS VARCHAR(10))
FROM C AS C2
WHERE C1.Item = C2.Item
ORDER BY C2.Col1
FOR XML PATH(''), TYPE
).value('substring(text()[1], 2)', 'VARCHAR(MAX)') AS Col2
FROM C AS C1
GROUP BY C1.Item
SQL Fiddle

Try this:
NOTE: Not tested
select col1, [col2],
(select col1+',' from Table2 where Col2=ID
group by col1 for xml path('')) AS Col2
From Table1

Related

Extract tuples with specified common values in another column in SQL

I have a dataset that look like:
Col1 Col2
1 ABC
2 DEF
3 ABC
1 DEF
Expected output:
Col1 Col2
1 ABC
1 DEF
I want to extract only those IDSs from Col1 which have both values ABC and DEF in the column.
I tried the self-join in SQL but that did not give me the expected result.
SELECT DISTINCT Col1
FROM db A, db B
WHERE A.ID <> B.ID
AND A.Col2 = 'ABC'
AND B.Col2 = 'DEF'
GROUP BY A.Col1
Also, I tried to the same thing in R using the following code:
vc <- c("ABC", "DEF")
data1 <- db[db$Col2 %in% vc,]
Again, I did not get the desired output. Thanks for all the pointers in advance.
In R, you could do
library(dplyr)
df %>%
group_by(Col1) %>%
filter(all(vc %in% Col2))
# Col1 Col2
# <int> <fct>
#1 1 ABC
#2 1 DEF
The Base R equivalent of that would be
df[as.logical(with(df, ave(Col2, Col1, FUN = function(x) all(vc %in% x)))), ]
# Col1 Col2
#1 1 ABC
#4 1 DEF
We select the groups which has all of vc in them.
Here is your current query corrected:
SELECT DISTINCT t1.Col1
FROM yourTable t1
INNER JOIN yourTable t2
ON t1.Col1 = t2.Col1
WHERE t1.Col2 = 'ABC' AND t2.Col2 = 'DEF';
Demo
The join condition is that both Col1 values are the same, the first Col2 value is ABC and the second Col2 value is DEF.
But, I would probably use the following canonical approach to this:
SELECT Col1
FROM yourTable
WHERE Col2 IN ('ABC', 'DEF')
GROUP BY Col1
HAVING MIN(Col2) <> MAX(Col2);
In R, we can also use data.table
library(data.table)
setDT(df)[, .SD[all(vc %in% Col2)], by = col1]
Use correlated subquery:
select * from tablename t
where exists (select 1 from tablename t1 where t1.col1=t.col1 and col2 in ('ABC','DEF')
group by col1 having count(distinct col2)=2)
Here's a way using group_concat
select t.Col1,t.col2
from t
join
(
select col1,group_concat(distinct col2 order by col2) gc
from t
group by col1 having gc = 'abc,def'
) s
on s.col1 = t.col1;
+------+------+
| Col1 | col2 |
+------+------+
| 1 | ABC |
| 1 | DEF |
+------+------+
2 rows in set (0.16 sec)
But you do have to understand the order that col2 will be in

how to achieve concatenation using group by

Suppose there is a table named 'a' with following data:
col1, col2
-----------
1 1
1 2
1 3
2 2
2 3
3 4
then to achieve following results:
col1, col2
--------------
1 6
2 5
3 4
i can run query like :
select col1, sum(col2) from a group by col1.
But suppose my table is:
col1, col2
---------
1 a
1 b
1 c
2 d
2 e
3 f
here col2 is of varchar type not of numeric type.
what will be the sql query to give following results???
col1, col2
------------
1 a,b,c
2 d,e
3 f
i have tried group by on col1 but how to concatenate values in col2???
the problem is that col2 is of varchar type.
In case of MySQL you can use GROUP_CONCAT like this:
SELECT
col1,
GROUP_CONCAT(col2) as col2
FROM demo
GROUP BY col1;
Here is the sqlfiddle.
In case of SQL Server you can use STUFF like this:
SELECT t1.col1,
stuff((SELECT ',' + CAST(t2.col2 as VARCHAR(10))
FROM demo t2 WHERE t1.col1 = t2.col1
FOR xml path('')),1,1,'') col2
FROM demo t1
GROUP BY t1.col1;
Here is the sqlfiddle.
You can use group_concat function in mysql
select
col1,
group_concat(col2) as col2
from table_name
group by col1
Here is a good example, I ran into a similar issue whilst coding up a schedule (working example: www.oldiesplus.com/schedule/)
Here is the link to my question with answer: https://stackoverflow.com/a/27047139

select a field values that are not found in another table

I need a query which should results a fields that are not found in another table. Let say,
table 1:
comp col1 col2 col3 col4
----------------------------------
nam1 1 1 b c
nam2 0 0 abc c
nam3 1 1 a c
nam4 1 1 b c
nam5 0 0 c c
table2:
name col1 col2
----------------------
b 3 f
a 4 f
c 5 f
result:
comp col3 col4
----------------------
nam2 abc c
the result be based on col3,col1=0,col2=0 on first table and name in second table..abc is not found in table2...
thanks in advance.
The question is not very clear, but if I understood you correctly, you want to select all rows from table1 where col1 and col2 are both 0, and col3 is not contained in the name column of table2. If so, your query should be simple enough:
SELECT comp, col3, col4
FROM table1
WHERE col1 = 0
AND col2 = 0
AND col3 NOT IN (SELECT name FROM table2);
As per the explanation the joining key between table1 and table2 is
table1.col3 = table2.name
Using this you can use the following query
select
t1.comp,
t1.col3,
t1.col4
from table1 t1
left join table2 t2 on t2.name = t1.col3
where t2.name is null

Show only differences between two rows in mysql

Having a (MySQL) audit table containing rows that are similar, is it possible to view only those columns that have different values?
For example, a table containing four columns where column key is primary key, and column id is the identifier to match rows:
key id col1 col2
1 123 B C
2 123 A C
3 456 B C
4 789 B A
5 789 B B
6 987 A C
In the example above I need the query to return only row 1, 2, 4, and 5 as they have matching id, and differing values in col1 and col2, ie B,A and B,A.
key id col1 col2
1 123 B
2 123 A
4 789 A
5 789 B
I know it might not be very efficient solution, but gives what you want. HERE try this:
SELECT A.ID, (CASE A.col1 WHEN B.col1 THEN NULL ELSE B.col1 END), (CASE A.col2 WHEN B.col2 THEN NULL ELSE B.col2 END) FROM tblName A
FULL OUTER JOIN tblName B
ON
A.ID=B.ID
WHERE
(A.col1=B.col1 AND A.Col2<>B.Col2)
OR
(A.col2<>B.col2 AND A.Col1=B.Col1)
INNER JOIN should give same result
This is a bit contrived, in the sense that adding more rows will give very different results - but anyway...
SELECT x.my_key
, x.id
, IF(y.col1=x.col1,'',x.col1) col1
, IF(y.col2=x.col2,'',x.col2) col2
FROM my_table x
JOIN my_table y
ON y.id = x.id
AND y.my_key <> x.my_key
WHERE (y.col1 <> x.col1 OR y.col2 <> x.col2)
ORDER
BY my_key;
Thanks for all responses which guided me.
Using your suggestions I made the sql like this:
SELECT
T1.KEY,
T1.ID,
CASE T2.COL1_DISTINCT_VALUES WHEN 1 THEN NULL ELSE T1.COL1 END AS COL1,
CASE T2.COL2_DISTINCT_VALUES WHEN 1 THEN NULL ELSE T1.COL2 END AS COL2
FROM
TAB1 T1
INNER JOIN
(
SELECT
ID,
COUNT(DISTINCT COL1) AS COL1_DISTINCT_VALUES,
COUNT(DISTINCT COL2) AS COL2_DISTINCT_VALUES
FROM
TAB1
GROUP BY
ID
) T2
ON T1.ID=T2.ID
WHERE
T2.COL1_DISTINCT_VALUES > 1
OR T2.COL2_DISTINCT_VALUES > 1
ORDER BY
KEY,ID;

Grouping problem

When you use Group By how do you keep the other fields in sync when using aggregates
Here I am trying to find the min value of col4 when col2 = xxx
select col1, col2, col3, min(col4)
from table
where col2 = 'xxx'
group by col3
I can get the minimum value in col4 but col1 is not correct but col2, col3, col4 are.
Can anyone show me how to do this ?
Thanks
You are using non-standard MySQL extension to GROUP BY.
This query in fact reads as "for each distinct value of col3, select the minimal value of col4 along with the values of col1 and col2 from a single row of table having this value of col3 in no particular order"
Like, if we have the following data:
col1 col2 col3 col4
---- --- --- ----
A A 1 1
B B 1 2
C C 2 3
D D 2 4
, this query:
SELECT col1, col2, col3, MIN(col4)
FROM mytable
GROUP BY
col3
will return either of the following:
col1 col2 col3 col4
---- --- --- ----
A A 1 1
C C 2 3
col1 col2 col3 col4
---- --- --- ----
B B 1 1
C C 2 3
col1 col2 col3 col4
---- --- --- ----
A A 1 1
D D 2 3
col1 col2 col3 col4
---- --- --- ----
B B 1 1
D D 2 3
i. e. it can return any value of col1 and col2 found in the rows that contribute to the corresponding group.
This is equivalent of FIRST_VALUE analytic function, but in no particular order.
Update:
To select values of col1 and col2 corresponding to the minimal value of col4 within each group, use this:
SELECT col1, co2, col3, col4
FROM (
SELECT col1, col2, col3, col4,
COALESCE(#col3 = col3, FALSE) AS grp,
#col3 := col3 AS nv
FROM (
SELECT #col3 := NULL
) vars, table
WHERE col2 = 'xxx'
ORDER BY
col3, col4
) q
WHERE NOT grp
select a.col3, a.col2, a.col1, a.col4
from table as a natural join
(select col3, min(col4) as col4 from table
where col2='xxx'
group by col3 ) as b
where a.col2 = 'xxx' -- sometimes this helps the optimizer even though it's redundant
you can get into a bit of trouble here when there may be multiple rows with the same col3, col4, and col2, but different col1s -- pretty straightforward to fix with rownums and such, but that gets db-specific.
I guess you want the col1-3 corresponding to the min(col4) for each
col3?
Something like:
select X.col1, X.col2, X.col3, X.col4 from table X
join (select col3, min(col4) as mcol4 from table where col2='xxx' group by col3) as Y
on X.col3=Y.col3 and X.col4=Y.mcol4
where X.col2='xxx';