How can I get any row which substring is any? - sql

I have a table with a varchar(max). I would like to know if it's possible to get all rows that contains any substring from a list of it.
I know that for one value I can use like 'AAA%', but I don't know if like has any way to say something like where IN().
Something like this:
select * from TableA where
TableA.Field1 contains any (select Fild1 from TableB where field2 > 5);
Where TableA.Field 1 and TableB.Field1 are varchar(max).
Thank you so much.

select * from TableA
where exists (select 1 from TableB
where TableA.Field1 like '%' + TableB.Fild1 + '%'
and TableB.field2 > 5)

SQL Server includes the CONTAINS function so something like this will work fine.
SELECT *
FROM TableA
JOIN TableB ON CONTAINS(TableA.Field1, TableB.Fild1) AND TableB.field2 > 5
You may need to adjust for your requirements.
Here is the documentation on contains
https://msdn.microsoft.com/en-us/library/ms187787.aspx

You can use a dynamic sql query.
Query
declare #query varchar(max)
select #query = 'select * from t1 where ' +
STUFF
(
(
select ' OR col1 like ''' + col1 + '%'''
from t2
for xml path('')
),
1,4,'');
execute(#query);
Example
Table - t1
+----+-------+
| id | col1 |
+----+-------+
| 1 | AAAAA |
| 2 | BBBBB |
| 3 | CCCCC |
| 4 | DDDDD |
| 5 | EEEEE |
+----+-------+
Table - t2
+------+
| col1 |
+------+
| AA |
| BB |
| CC |
+------+
Output
+----+-------+
| id | col1 |
+----+-------+
| 1 | AAAAA |
| 2 | BBBBB |
| 3 | CCCCC |
+----+-------+

Related

Insert value into a table when strings match conditions from another table

I have two tables in a PostgreSQL database. Table2 has an FK from table1's PK. I want to search table1 for specific strings, and if I find matches I want to update a column in table2 with a string.
Table1
+----+------+------+------+
| PK | Col1 | Col2 | Col3 |
+----+------+------+------+
| 1 | A | x | x |
| 2 | x | x | x |
| 3 | x | A | x |
| 4 | x | x | x |
| 5 | x | x | A |
+----+------+------+------+
Table2
+----+-----------------+
| FK | matching_column |
+----+-----------------+
| 1 | string |
| 2 | |
| 3 | string |
| 4 | |
| 5 | string |
+----+-----------------+
So where table1 contains '%A%'
update table2 with 'string'
I'm not sure where to start on this one. Does anyone have a solution?
Use a subquery:
UPDATE table2
SET matching_column = 'string'
WHERE fk = (SELECT pk
FROM table1
WHERE "Col1" LIKE '%A%'
OR "Col2" LIKE '%A%'
OR "Col3" LIKE '%A%');
You could use the update ... set ... from syntax. If I followed you correctly, you want:
update table2 t2
set t2.matching_column = 'string'
from table 1 t1
where
t1.pk = t2.fk
and 'A' in (t1.col1, t1.col2, t1.col3)
This phrases as: if the fk of table2 exists in table1 and one of the 3 columns contains (col1, col2, col3) contains 'A', then set column matching_column in the corresponding record in table2 to 'string'.

SQL Server select column names from multiple tables

I have three tables in SQL Server with following structure:
col1 col2 a1 a2 ... an,
col1 col2 b1 b2 ... bn,
col1 col2 c1 c2 ... cn
The two first records are the same, col1 and col2, however the tables have different lengths.
I need to select the column names of the tables and the result I'm trying to achieve is the followig:
col1, col2, a1, b1, c1, a2, b2, c2 ...
Is there a way to do it?
It's possible but result's is combined into single column of three table tables.
For example
SELECT A.col1 +'/' +B.col1 +'/' + C.col1 As Col1 ,
A.col2 +'/' +B.col2 +'/' + C.col2 As col2 ,a1, b1, c1, a2, b2, c2 ,
* FROM A
INNER JOIN B
ON A.ID =B.ID
INNER JOIN C
ON C.ID = B.ID
SQL-Server is not the right tool to create a generic resultset. The engine needs to know what's coming out in advance. Well, you might try to find a solution with dynamic SQL...
I want to suggest two different approaches.
Both would work with any number of tables, as long as all of them have the columns col1 and col2 with appropriate types.
Let's create a simple mokcup scenario before:
DECLARE #mockup1 TABLE(col1 INT,col2 INT,SomeMore1 VARCHAR(100),SomeMore2 VARCHAR(100));
INSERT INTO #mockup1 VALUES(1,1,'blah 1.1','blub 1.1')
,(1,2,'blah 1.2','blub 1.2')
,(1,100,'not in t2','not in t2');
DECLARE #mockup2 TABLE(col1 INT,col2 INT,OtherType1 INT,OtherType2 DATETIME);
INSERT INTO #mockup2 VALUES(1,1,101,GETDATE())
,(1,2,102,GETDATE()+1)
,(1,200,200,GETDATE()+200);
--You can add as many tables as you need
A very pragmatic approach:
Try this simple FULL OUTER JOIN:
SELECT *
FROM #mockup1 m1
FULL OUTER JOIN #mockup2 m2 ON m1.col1=m2.col1 AND m1.col2=m2.col2
--add more tables here
The result
+------+------+-----------+-----------+------+------+------------+-------------------------+
| col1 | col2 | SomeMore1 | SomeMore2 | col1 | col2 | OtherType1 | OtherType2 |
+------+------+-----------+-----------+------+------+------------+-------------------------+
| 1 | 1 | blah 1.1 | blub 1.1 | 1 | 1 | 101 | 2019-03-08 10:53:20.257 |
+------+------+-----------+-----------+------+------+------------+-------------------------+
| 1 | 2 | blah 1.2 | blub 1.2 | 1 | 2 | 102 | 2019-03-09 10:53:20.257 |
+------+------+-----------+-----------+------+------+------------+-------------------------+
| 1 | 100 | not in t2 | not in t2 | NULL | NULL | NULL | NULL |
+------+------+-----------+-----------+------+------+------------+-------------------------+
| NULL | NULL | NULL | NULL | 1 | 200 | 200 | 2019-09-24 10:53:20.257 |
+------+------+-----------+-----------+------+------+------------+-------------------------+
But you will have to deal with non-unique column names... (This is the moment, where a dynamically created statement can help).
A generic approach using container type XML
Whenever you do not know the result in advance, you can pack the result in a container. This allows a clear structure on the side of your RDBMS and shifts the troubles how to deal with this set to the consumer.
The cte will read all existing pairs of col1 and col2
Each table's row(s) for the pair of values is inserted as XML
Pairs not existing in any of the tables show up as NULL
Try this out
WITH AllDistinctCol1Col2Values AS
(
SELECT col1,col2 FROM #mockup1
UNION ALL
SELECT col1,col2 FROM #mockup2
--add all your tables here
)
SELECT col1,col2
,(SELECT * FROM #mockup1 x WHERE c1c2.col1=x.col1 AND c1c2.col2=x.col2 FOR XML PATH('row'),TYPE) AS Content1
,(SELECT * FROM #mockup2 x WHERE c1c2.col1=x.col1 AND c1c2.col2=x.col2 FOR XML PATH('row'),TYPE) AS Content2
FROM AllDistinctCol1Col2Values c1c2
GROUP BY col1,col2;
The result
+------+------+-----------------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------+
| col1 | col2 | Content1 | Content2 |
+------+------+-----------------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------+
| 1 | 1 | <row><col1>1</col1><col2>1</col2><SomeMore1>blah 1.1</SomeMore1><SomeMore2>blub 1.1</SomeMore2></row> | <row><col1>1</col1><col2>1</col2><OtherType1>101</OtherType1><OtherType2>2019-03-08T11:03:49.877</OtherType2></row> |
+------+------+-----------------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------+
| 1 | 2 | <row><col1>1</col1><col2>2</col2><SomeMore1>blah 1.2</SomeMore1><SomeMore2>blub 1.2</SomeMore2></row> | <row><col1>1</col1><col2>2</col2><OtherType1>102</OtherType1><OtherType2>2019-03-09T11:03:49.877</OtherType2></row> |
+------+------+-----------------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------+
| 1 | 100 | <row><col1>1</col1><col2>100</col2><SomeMore1>not in t2</SomeMore1><SomeMore2>not in t2</SomeMore2></row> | NULL |
+------+------+-----------------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------+
| 1 | 200 | NULL | <row><col1>1</col1><col2>200</col2><OtherType1>200</OtherType1><OtherType2>2019-09-24T11:03:49.877</OtherType2></row> |
+------+------+-----------------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------+

Creating New Table by select query with sequental column names

I have a table that contains column names like this;
+--------------------------------------------------------------------+-----------+
| BankTable | |
+--------------------------------------------------------------------+-----------+
| Id | BANK1 | BANK2 | BRANCH1 | BRANCH2 | IBAN1 | IBAN2 |
+----+-----------+-----------+-------------+-------------+-----------+-----------+
| 1 | BANK1_ID1 | BANK2_ID1 | BRANCH1_ID1 | BRANCH2_ID1 | IBAN1_ID1 | IBAN2_ID1 |
+----+-----------+-----------+-------------+-------------+-----------+-----------+
| 2 | BANK1_ID2 | BANK2_ID2 | BRANCH1_ID2 | BRANCH1_ID2 | IBAN1_ID2 | IBAN2_ID2 |
+----+-----------+-----------+-------------+-------------+-----------+-----------+
How can i write a query that returns the result like this;
+------------------------------------------+
| BANK |
+------------------------------------------+
| ID | BANK | BRANCH | IBAN |
+----+-----------+-------------+-----------+
| 1 | BANK1_ID1 | BRANCH1_ID1 | IBAN1_ID1 |
+----+-----------+-------------+-----------+
| 2 | BANK2_ID2 | BRANCH1_ID2 | IBAN2_ID2 |
+----+-----------+-------------+-----------+
P.s: I am writing select query by Id column. BTW query result contains one row every time.
Any help appreciated.
SOLUTION
I don't know if it's good approach but i solved this by based on #Giorgos Betsos answer. Here is how i fixed this problem.
SELECT BANK, BRANCH, IBAN
FROM (
SELECT BANK1, BANK2, BRANCH1, BRANCH2, IBAN1, IBAN2
FROM BankTable
WHERE ID = your_id_here
) AS src
UNPIVOT (
BANK FOR Col IN(BANK1, BANK2)
) AS unpvt1
UNPIVOT (
BRANCH FOR Col1 IN(BRANCH1, BRANCH2)
) AS unpvt2
UNPIVOT (
IBAN FOR Col2 IN(IBAN1, IBAN2)
) AS unpvt3
WHERE RIGHT(Col, 1) = RIGHT(Col1, 1)
AND RIGHT(Col, 1) = RIGHT(Col2, 1)
You can use UNPIVOT for this:
SELECT Bank
FROM (
SELECT Id, BANK1, BANK2, BANK3, BANK4, BANK5
FROM BankTable
WHERE id = 1) AS src
UNPIVOT (
Bank FOR Col IN([BANK1], [BANK2], [BANK3], [BANK4], [BANK5])) AS unpvt
Demo here
If number of column is more, then you can use a dynamic sql query as below:
Query
declare #sql as varchar(max);
select #sql =stuff(
(select 'union all select [' + column_name + '] as Bank
from BankTable where Id = 1 '
from information_schema.columns
where table_name = 'BankTable'
and column_name like 'BANK[0-9]%'
for xml path('')), 1, 9, '');
execute(#sql);
Result
+-----------+
| Bank |
+-----------+
| BANK1_ID1 |
| BANK2_ID1 |
| BANK3_ID1 |
| BANK4_ID1 |
| BANK5_ID1 |
+-----------+

Using SWITCH() to split data from a column into distinct columns, with associated data in reach row

I'm not quite sure how to properly phrase the question, but I am basically trying to develop an SQL query that SELECTs information from this table:
-------------------
| id | Val | Date |
|----|-----|------|
| 1 | A | 10/9 |
| 1 | B | 3/14 |
| 2 | A | 1/6 |
| 3 | A | 4/4 |
| 4 | B | 7/12 |
| 5 | A | 8/6 |
-------------------
And produces a table that looks like this:
------------------------------------------------
| id | Val_1 | Val_1_Date | Val_2 | Val_2_Date |
|----|-------|------------|-------|-------------
| 1 | A | 10/9 | B | 3/14 |
| 2 | A | 1/6 | | |
| 3 | A | 4/4 | | |
| 4 | | | B | 7/12 |
| 5 | A | 8/6 | | |
------------------------------------------------
I have already begun and developed the query to pull out the values in the Val fields into distinct columns:
SELECT * FROM
(
SELECT id, MAX(SWITCH( val='A', 'A')) as Val_1,
MAX(SWITCH( val='B', 'B')) as Val_2
FROM table1 GROUP BY id
)a
WHERE Val_1 IS NULL OR Val_2 IS NULL;
How would I expand on this to pull out their associated dates?
(I am using SWITCH() instead of CASE WHEN because I am using a driver similar to that of MS Access.)
Thanks!
I think following should work:
select id, SWITCH( val='A', 'A') as Val_1, SWITCH( val='A', Date) as Val_1_Date, SWITCH( val='B', 'B') as Val_2, SWITCH( val='B', Date) as Val_2_Date FROM table1 GROUP BY id
I do not prefer switches, so here is a query that does what you want without switches. This also answers your previous question.
Select distinct table1.ID, tableA.Val as Val_1, tableA.Date as Val_1_Date,
tableB.Val as Val_2, tableB.Date as Val_2_Date
FROM table1 left outer join
table1 as tableA on table1.id = tableA.id and tableA.Val = 'A' left outer join
table1 as tableB on table1.id = tableB.id and tableB.Val = 'B'
You can use ISNULL if that is preferred. This works because the first tables selects a distinct column of ID's, and the two joins get the A and B values. When creating selects using this method, make sure that you use tableA.Val = 'A' in the join conditions, and not in the where clause. Having tableA.Val = 'A' in the where clause will filter out all NULL's.

Row into column SQL Server 2005/8

I've just started to get into SQL Server deeper and I have a problem. I have to transform a row into a column, but I can't figure it out.
The row looks like this:
Columns: T1 T2 T3 .........T20
Values: 1 0 9 ......... 15
I want to receive something like this:
Col Val
________
T1 1
T2 0
T3 9
........
T20 15
I know i have to use a pivot, i have read about this, but can't figure it out
You have to use UNPIVOT table operator for this, like this:
SELECT col, val
FROM Tablename AS t
UNPIVOT
(
Val
FOR Col IN (T1, T2, ..., T20)
) AS u;
SQL Fiddle Demo.
Update 1
If you want to do this dynamically for any number of columns, without the need to write them manually, the only way I can think of is by reading these columns from the table information_schema.columns to get the list of columns' names of the table. Then use dynamic SQL to compose the statement FOR col IN ... dynamically like this:
DECLARE #cols AS NVARCHAR(MAX);
DECLARE #query AS NVARCHAR(MAX);
select #cols = STUFF((SELECT distinct ',' +
QUOTENAME(column_name)
FROM information_schema.columns
WHERE table_name = 'tablename'
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
, 1, 1, '');
SELECT #query = ' SELECT col, val
FROM tablename AS t
UNPIVOT
(
val
FOR col IN ( ' + #cols + ' )
) AS u;';
EXECUTE(#query);
Updated SQL Fiddle Demo
This will give you:
| COL | VAL |
-------------
| T1 | 1 |
| T10 | 15 |
| T11 | 33 |
| T12 | 31 |
| T13 | 12 |
| T14 | 10 |
| T15 | 12 |
| T16 | 9 |
| T17 | 10 |
| T18 | 2 |
| T19 | 40 |
| T2 | 0 |
| T20 | 21 |
| T3 | 9 |
| T4 | 2 |
| T5 | 3 |
| T6 | 10 |
| T7 | 14 |
| T8 | 15 |
| T9 | 20 |