SQL Server Syntax - Using in or like with comma delimited columns - sql-server

I have two tables where I want to check if a value exists in the second table.
The problem is that in the second table the group field could either be a individual value or a comma delimited value. I need a query to check if the group value exists in table 2 either as a single value or in a comma delimited value
Table 1
Id
Group
1
Group1
2
Group2
3
Group3
5
Group4
6
Group4
7
Group2
Table 2
Group
Group1, Group2
Group3
The results of the select query would be.
Table 1 Filtered Results
Id
Group
1
Group1
2
Group2
3
Group3
7
Group2

Ideally, you should not store multiple pieces of information in a single column.
But you can solve this in set-based fashion, using STRING_SPLIT in a subquery.
SELECT *
FROM t1
WHERE t1.[group] IN (
SELECT TRIM(s.value)
FROM t2
CROSS APPLY STRING_SPLIT(t2.[group], ',') s
);
db<>fiddle

Maybe this is what you want:
select * from Table1 t1 where exists (
select * from Table2 t2 where t2.[Group] like '%'+t1.[Group]+'%'
)
But be careful!!! "Group" is a keyword in SQL, you should not name a field like that.
UPDATE on Larnu comment:
To avoid Group1 and Group10 match, we can do that:
select * from Table1 t1 where exists (
select * from Table2 t2 where (t2.[Group] like '%'+t1.[Group] or t2.[Group] like '%'+t1.[Group]+',%')
)

Try joining the two tables with a LIKE clause, like this:
DECLARE #t1 TABLE (id INT, [group] VARCHAR(255))
DECLARE #t2 TABLE ([group] VARCHAR(255))
INSERT INTO #t1 VALUES (1,'g1'),(2,'g2'),(3,'g3'),(5,'g4'),(6,'g4'),(7,'g2')
INSERT INTO #t2 VALUES ('g1,g2'),('g3')
SELECT DISTINCT t1.*
FROM #t1 t1 INNER JOIN #t2 t2
ON t2.[group] LIKE '%' + t1.[group] OR t2.[group] LIKE '%' + t1.[group] + ',%'
Result:
id
group
1
g1
2
g2
3
g3
7
g2
UPDATED to accommodate Larnu's comment to Carlos's post

Related

Query to get no of non matching rows count for two tables using Sql Server?

I have Two Tables.
Table1 :-
Col1
AAA
BBB
CCC
Table2 :-
Col1
AAA
BBB
ZZZ
I want to get output :- 2
in above two tables contains 2 matching rows and two non maching rows. How to write Sql query to get count for non matching rows.
To get the number of non-matching rows, one simple way of doing it would be as shown below. We get the number of rows in Table1 that are not present in Table2, we get the number of rows in Table2 not in Table1, and we add both. UNION ALL combines the results of both queries (we use this instead of UNION because UNION discards duplicates).
SELECT SUM(NonMatchingRows) AS TotalNonMatchingRows
FROM (
-- Rows from Table1 that don't have a match in Table2
SELECT COUNT(*) AS NonMatchingRows
FROM Table1
WHERE Col1 NOT IN ( SELECT DISTINCT Col1 FROM Table2 )
UNION ALL
-- Rows from Table2 that don't have a match in Table1
SELECT COUNT(*) AS NonMatchingRows
FROM Table2
WHERE Col1 NOT IN ( SELECT DISTINCT Col1 FROM Table1 )
) AS X
To get the number of matching rows, you'd run:
SELECT COUNT(*) AS MatchingRows
FROM Table1
INNER JOIN Table2
ON Table1.Col1 = Table2.Col1
This inner join returns only the rows that have the same values for Col1 in both tables. Note that in case one single row in Table 1 matches 2 rows in Table 2, this query will return 2.

SQL joined table pivot without aggregate

I have two tables:
Table1
ID TYPE
1 ABC1
2 ABC2
3 ABC3
Table2
ID Data
1 100
1 101
2 10
2 90
And I want the results to look like this:
ID Data1 Data2
1 100 101
2 10 90
But I'm having a total mare with my attempts at creating the pivot. So far I have:
With Inital_Data As (
Select
A.ID,
B.Data As Data1,
B.Data As Data2
From
Table1 A join
Table2 B on
A.ID = B.ID
)
Select *
From
Initial_Data
PIVOT
(Max(ID) FOR Data IN (Data1,Data2)) p
I know this is rubbish but so far even the logic of what I'm trying to achieve is escaping me, let alone the syntax! Can anyone give me a guiding hand?
Pivot with more than one column needs some tricks, I prefer the XML concatenation. First I take all values for each ID in only one XML, then you can take these values one by one:
Just paste this into an empty query window and execute. Adapt for your needs
EDIT: Includes column Type from TABLE1 as Caption for ID...
DECLARE #Table1 TABLE(ID INT,[TYPE] VARCHAR(10));
INSERT INTO #Table1 VALUES
(1,'ABC1')
,(2,'ABC2')
,(3,'ABC3');
DECLARE #Table2 TABLE(ID INT,DATA INT);
INSERT INTO #Table2 VALUES
(1,100)
,(1,101)
,(2,10)
,(2,90);
WITH DistinctIDs AS
(
SELECT DISTINCT tbl2.ID,tbl1.[TYPE]
FROM #Table2 AS tbl2
INNER JOIN #Table1 AS tbl1 ON tbl1.ID=tbl2.ID
)
SELECT ID,[TYPE]
,concatXML.x.value('/root[1]/item[1]/#data','int') AS Data1
,concatXML.x.value('/root[1]/item[2]/#data','int') AS Data2
FROM DistinctIDs AS dIDs
CROSS APPLY
(
SELECT ID AS [#id],DATA AS [#data]
FROM #Table2 AS tbl WHERE tbl.ID=dIDs.ID
FOR XML PATH('item'), ROOT('root'),TYPE
) AS concatXML(x)

inner join and group by

I have two tables with identical definition.
T1:
Name VARCHAR(50)
Qty INT
T2:
Name VARCHAR(50)
Qty INT
This is the data each table has:
T1:
Name Qty
a 1
b 2
c 3
d 4
T2:
Name Qty
a 1
b 3
e 5
f 10
I want to have result which can sum the Qty from both the tables based on Name.
Expected resultset:
Name TotalQty
a 2
b 5
c 3
d 4
e 5
f 10
If am do Left Join or Right Join, it is not going to return me the Name from either of the tables.
What i am thinking is to create a temp table and add these records and just do a SUM aggregate on Qty column but i think there should be a better way to do this.
This is how my query looks like which does not return the expected resultset:
SELECT t1.Name, ISNULL(SUM(t1.Qty + t2.Qty),0) TotalQty
FROM t1
LEFT JOIN t2
ON t1.Name = T2.Name
GROUP BY t1.Name
Can someone please tell me if creating a temp table is OK here or there is a better way to do this?
You can use a full outer join:
SELECT
ISNULL(t1.Name, t2.Name) AS Name,
ISNULL(t1.Qty, 0) + ISNULL(t2.Qty, 0) AS TotalQty
FROM t1
FULL JOIN t2 ON t1.Name = T2.Name
See it working online: sqlfiddle
You can use a UNION ALL to select both tables as one, since they have the same definition. From there, you can nest them as a derived table, and then SUM on that:
SELECT [Name], SUM(Qty) AS TotalQty
FROM (
SELECT [Name], Qty
FROM t1
UNION ALL
SELECT [Name], Qty
FROM t2
) YourDerivedTable
GROUP BY [Name]

SQL server code (UPDATE)

i have a problem of how to update data from table A to table B and make in horizontal from vertical..example is
Table A ----------- Table B
ID ----- Item ----------- ID ------Item
11--- iPhone4 ----------- 11 ------iPhone4,iPhone4s,iPhone5
11--- iPhone4s
11--- iPhone5
mean that from 3 Rows become 1 rows.
Please help,really noob in this case..
Thanks
Try with this..
Select ID,
Left(Item,Len(Item)-1) As Items
From(
Select distinct T2.ID,
(Select
T1.Item + ',' AS [text()]
From TableA T1
where T1.ID = T2.ID
For XML PATH ('')) [item]
From dbo.TableA T2
) t
Try this..Use GROUP_CONCAT to merge in one row the rows you want to merge.
SELECT ID,GROUP_CONCAT(item)
FROM yourtable
GROUP BY ID;

Combine multiple results in a subquery into a single comma-separated value

I've got two tables:
TableA
------
ID,
Name
TableB
------
ID,
SomeColumn,
TableA_ID (FK for TableA)
The relationship is one row of TableA - many of TableB.
Now, I want to see a result like this:
ID Name SomeColumn
1. ABC X, Y, Z (these are three different rows)
2. MNO R, S
This won't work (multiple results in a subquery):
SELECT ID,
Name,
(SELECT SomeColumn FROM TableB WHERE F_ID=TableA.ID)
FROM TableA
This is a trivial problem if I do the processing on the client side. But this will mean I will have to run X queries on every page, where X is the number of results of TableA.
Note that I can't simply do a GROUP BY or something similar, as it will return multiple results for rows of TableA.
I'm not sure if a UDF, utilizing COALESCE or something similar might work?
Even this will serve the purpose
Sample data
declare #t table(id int, name varchar(20),somecolumn varchar(MAX))
insert into #t
select 1,'ABC','X' union all
select 1,'ABC','Y' union all
select 1,'ABC','Z' union all
select 2,'MNO','R' union all
select 2,'MNO','S'
Query:
SELECT ID,Name,
STUFF((SELECT ',' + CAST(T2.SomeColumn AS VARCHAR(MAX))
FROM #T T2 WHERE T1.id = T2.id AND T1.name = T2.name
FOR XML PATH('')),1,1,'') SOMECOLUMN
FROM #T T1
GROUP BY id,Name
Output:
ID Name SomeColumn
1 ABC X,Y,Z
2 MNO R,S
1. Create the UDF:
CREATE FUNCTION CombineValues
(
#FK_ID INT -- The foreign key from TableA which is used
-- to fetch corresponding records
)
RETURNS VARCHAR(8000)
AS
BEGIN
DECLARE #SomeColumnList VARCHAR(8000);
SELECT #SomeColumnList =
COALESCE(#SomeColumnList + ', ', '') + CAST(SomeColumn AS varchar(20))
FROM TableB C
WHERE C.FK_ID = #FK_ID;
RETURN
(
SELECT #SomeColumnList
)
END
2. Use in subquery:
SELECT ID, Name, dbo.CombineValues(FK_ID) FROM TableA
3. If you are using stored procedure you can do like this:
CREATE PROCEDURE GetCombinedValues
#FK_ID int
As
BEGIN
DECLARE #SomeColumnList VARCHAR(800)
SELECT #SomeColumnList =
COALESCE(#SomeColumnList + ', ', '') + CAST(SomeColumn AS varchar(20))
FROM TableB
WHERE FK_ID = #FK_ID
Select *, #SomeColumnList as SelectedIds
FROM
TableA
WHERE
FK_ID = #FK_ID
END
In MySQL there is a group_concat function that will return what you're asking for.
SELECT TableA.ID, TableA.Name, group_concat(TableB.SomeColumn)
as SomColumnGroup FROM TableA LEFT JOIN TableB ON
TableB.TableA_ID = TableA.ID
I think you are on the right track with COALESCE. See here for an example of building a comma-delimited string:
http://www.sqlteam.com/article/using-coalesce-to-build-comma-delimited-string
You may need to provide some more details for a more precise response.
Since your dataset seems kind of narrow, you might consider just using a row per result and performing the post-processing at the client.
So if you are really looking to make the server do the work return a result set like
ID Name SomeColumn
1 ABC X
1 ABC Y
1 ABC Z
2 MNO R
2 MNO S
which of course is a simple INNER JOIN on ID
Once you have the resultset back at the client, maintain a variable called CurrentName and use that as a trigger when to stop collecting SomeColumn into the useful thing you want it to do.
Assuming you only have WHERE clauses on table A create a stored procedure thus:
SELECT Id, Name From tableA WHERE ...
SELECT tableA.Id AS ParentId, Somecolumn
FROM tableA INNER JOIN tableB on TableA.Id = TableB.F_Id
WHERE ...
Then fill a DataSet ds with it. Then
ds.Relations.Add("foo", ds.Tables[0].Columns("Id"), ds.Tables[1].Columns("ParentId"));
Finally you can add a repeater in the page that puts the commas for every line
<asp:DataList ID="Subcategories" DataKeyField="ParentCatId"
DataSource='<%# Container.DataItem.CreateChildView("foo") %>' RepeatColumns="1"
RepeatDirection="Horizontal" ItemStyle-HorizontalAlign="left" ItemStyle-VerticalAlign="top"
runat="server" >
In this way you will do it client side but with only one query, passing minimal data between database and frontend
I tried the solution priyanka.sarkar mentioned and the didn't quite get it working as the OP asked. Here's the solution I ended up with:
SELECT ID,
SUBSTRING((
SELECT ',' + T2.SomeColumn
FROM #T T2
WHERE WHERE T1.id = T2.id
FOR XML PATH('')), 2, 1000000)
FROM #T T1
GROUP BY ID
Solution below:
SELECT GROUP_CONCAT(field_attr_best_weekday_value)as RAVI
FROM content_field_attr_best_weekday LEFT JOIN content_type_attraction
on content_field_attr_best_weekday.nid = content_type_attraction.nid
GROUP BY content_field_attr_best_weekday.nid
Use this, you also can change the Joins
SELECT t.ID,
t.NAME,
(SELECT t1.SOMECOLUMN
FROM TABLEB t1
WHERE t1.F_ID = T.TABLEA.ID)
FROM TABLEA t;
This will work for selecting from different table using sub query.
I have reviewed all the answers. I think in database insertion should be like:
ID Name SomeColumn
1. ABC ,X,Y Z (these are three different rows)
2. MNO ,R,S
The comma should be at previous end and do searching by like %,X,%

Resources