Snowflake- Pattern Matching with Inner join - snowflake-cloud-data-platform

In snowflake Can we join on a column between 2 tables based on regex/substring instead of exact equality?
For example In Table A/Column A and Table B/Column B, fetch all the records where Column A is a substring of Column B.
I referred REGEXP_SUBSTR, SUBSTR, SUBSTRING and CONTAINS functions of the snowflake, but couldn't figure out how to use it as part of Inner JOIN.

You can do it with substrings, charindex functions, and probably some regexp commands too, here are a couple overly simple examples.
CREATE TABLE table_a (column_a VARCHAR(100));
INSERT INTO table_a VALUES ('hello world'),('testing 123'),
('I like Jelly'),('this is a good question');
CREATE TABLE table_b (column_b VARCHAR(100));
INSERT INTO table_b VALUES ('this is table b'),('world'),
('jelly'),('Netflix or Hulu?'),('Goodbye');
SELECT a.*
FROM table_a a
INNER JOIN table_b b
ON SUBSTR(a.column_a, CHARINDEX(' ', a.column_a) + 1, length(a.column_a))
= b.column_b;
--1 row selected, 'hello world'
SELECT a.*, b.*
FROM table_a a,
table_b b
WHERE CHARINDEX(UPPER(b.column_b), UPPER(a.column_a)) > 0;
--2 rows selected, 'hello world'/world & 'I like Jelly'/jelly

Related

SQL Server : add a new column using union

I have 2 tables which have 2 columns in common and 1 column is different in both table
Table A
Table B
I need to create a common table having the values as follows
Expected Output
I tried using join on Memid and Meas but it duplicates as the 2 field do not create unique set as shown in figure
I tried union but then I get a resultset like this
Output for Inner join with distinct condition
How do I go about achieving the desired result set?
Note: Just a note coincidentally in this case the 2 columns seems to have similar values but they can be different.
Basically I need to create this one table with the 4 columns where Payer and PPayer columns should be independent of each other.
You don't need to use UNION, you can try like following using INNER JOIN.
INSERT INTO NewTable (
UserId
,DEPT
,ROOM
,LAB
)
SELECT DISTINCT ta.UserId
,ta.DEPT
,ta.ROOM
,tb.LAB
FROM TableA ta
INNER JOIN TableB tb ON ta.UserId = tb.UserId
AND ta.DEPT = tb.DEPT
Check Working Demo
Shanawaz Khan, Try this Solution
Declare Sample Table
DECLARE #A as TABLE(
UserId INT,
DEPT VARCHAR(50),
ROOM INT)
DECLARE #B as TABLE(
UserId INT,
DEPT VARCHAR(50),
LAB VARCHAR(50))
Insert Sample Records in Created Table
INSERT INTO #A (UserId,DEPT,ROOM) VALUES(1,'A',1),(1,'B',1),(1,'A',2),(1,'B',2)
INSERT INTO #B (UserId,DEPT,LAB) VALUES(1,'A','P'),(1,'B','Q'),(1,'A','P'),(1,'B','Q')
Generate DEPT wise Row number for Both Tables and Insert into another Temptable
SELECT ROW_NUMBER() OVER(PARTITION BY A.DEPT ORDER BY A.ROOM ) AS Rno,* INTO #tbl_A FROM #A A
SELECT ROW_NUMBER() OVER(PARTITION BY B.DEPT ORDER BY B.LAB) AS Rno,* INTO #tbl_B FROM #B B
Final Query Using Inner Join
SELECT A.UserId,A.DEPT,A.ROOM,B.LAB FROM #tbl_A AS A
INNER JOIN #tbl_B AS B ON A.Rno =B.Rno AND A.DEPT =B.DEPT ORDER BY A.ROOM, B.DEPT
Drop Created Temptable
DROP TABLE #tbl_A,#tbl_B
OutPut

Update grouped rows with ID of newly inserted grouping row

I want to group several rows of table A and insert a new row into table B for each bunch of grouped rows.
Next to that I want to update the rows of table A with the ID of the newly inserted row.
Inserting the lines into the table with 'grouplines' is like:
INSERT INTO B(...,...,...)
SELECT col1, col2 FROM A
GROUP BY col1,col2
This will produce a list of IDs in table B. I want to update the rows of table A with the ID of the corresponding group-row of table B.
Is there a possibilty to do this?
Some sample data:
After grouping table B looks like:
And then table A should look like:
As it is, your query potentially inserts more than one row.
I think that one solution would to use two queries: first insert in table b from table a, the update table a with newly created id(s) from table b.
INSERT INTO B(col1, col2, col3)
SELECT DISTINCT col1, col2, col3 FROM A
UPDATE A
SET A.B_ID = B.B_ID
FROM A
INNER JOIN B
ON A.col1 = B.col1
AND A.col2 = B.col2
AND A.col3 = B.col3
Deme on db<>fiddle
You can achieve table B by using Row_Number like below
Select ROW_NUMBER() OVER(ORDER BY Category) as ID, Name, Category
into #B
from #A
group by Name, Category
Then Update the table A after joining with table B like
Update a
set a.ID_Of_Group_row = b.ID
from #A a
inner join #B b on a.Category = b.Category
Output

Selecting Columns A values if no like a value in column B in SQL Server

I have Table1
And I am trying to remove every identical Column A value if one of it's row has "ZX" anywhere in Column B. So if I did it right, it will look like Table2
I did the following:
Select
Column A,
Column B
From
Table1
Where
Column B not like '%ZX%'
However, it only removes rows with ZX and not every identical Column A values and returns this Table instead
I will really appreciate any help on this! Thank you in advance :)
You can use NOT IN
SELECT
ColumnA
, ColumnB
FROM table1
WHERE ColumnA NOT IN (SELECT ColumnA FROM table1 WHERE ColumnB like '%ZX%')
I like not exists for this purpose:
Select t1.*
From Table1 T1
where not exists (select 1 from table1 tt1 where tt1.a = t1.a and tt1.b like '%ZX%');
This can take advantage of an index on table1(a, b).
Use :NOT EXISTS and that should do it:
Select
[Column A],
[Column B]
From Table1 T1
where
NOT EXISTS (
SELECT 1 FROM TABLE1 T2
WHERE T2.[Column B] like '%ZX%'
AND T2.[column a] = t1.[column a]
)

Finding all records that do NOT join on inner join of two tables?

I have a SQL Server query for an inner join...
SELECT *
FROM tableA
INNER JOIN tableB on tableA.my_id = tableB.my_id
How would I find all the records that did NOT match in this join?
You can use a FULL JOIN to combine the two tables, then use a WHERE clause to filter the results down to only non-matching rows by checking for a NULL in each tables primary key value.
Full outer join All rows in all joined tables are included, whether they are matched or not.
SELECT a.pk, b.pk
FROM tableA a
FULL JOIN tableB b ON a.pk=b.fk
WHERE
a.pk IS NULL
OR b.pk IS NULL
SELECT A2.* FROM TableA A2
WHERE A2.my_id NOT IN
(Select tableA.my_id FROM
tableA
inner join
tableB
on tableA.my_id = tableB.my_id)
you could similarly do the above starting SELECT B2.* FROM TableB B2, in order to separately query unmatched records in Table B
if you want all records in one table you could UNION ALL the two queries, depending on the table field structures being the same or how you specify the fields you select - what are you doing with the data?
SELECT * FROM tableA where my_id NOT IN (SELECT my_id from tableB)
UNION ALL
SELECT * FROM tableB where my_id NOT IN (SELECT my_id from tableA)

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