How to do a LIKE search with another table's values? - join

I want to do a LIKE search on two tables. One table has a column of search terms and the other table has the column in which to perform the LIKE searches. Here are the tables:
create table #TableA
(
UserName Varchar(50)
)
create table #TableB
(
Department Varchar(50),
Keyword Varchar(50)
)
Insert Into #TableA VALUES('bob_sales')
Insert Into #TableA VALUES('mary_accounting')
Insert Into #TableA VALUES('sammi_accountant')
Insert Into #TableA VALUES('fred_bestSellerEver123')
Insert Into #TableB VALUES('Accounting', 'accounting')
Insert Into #TableB VALUES('Accounting', 'accountant')
Insert Into #TableB VALUES('Sales', 'sales')
Insert Into #TableB VALUES('Sales', 'seller')
I'd like to run a query that uses LIKE %keyword% and gives me:
bob_sales | Sales
mary_accounting | Accounting
sammi_accountant | Accounting
fred_bestSellerEver123 | Sales

Another method, without join, just for fun:
select department,
(select top 1 username from #tablea a
where a.username like '%' + b.keyword + '%') UserName
from #tableb b

SqlFiddleDemo
SELECT
ta.UserName
,tb.Department
FROM TableA ta
JOIN TableB tb
ON ta.UserName LIKE '%' + tb.[keyword] + '%'
/* If needed add COLLATE Latin1_General_CI_AS */
Remarks:
If your data can contains something like: sammi_accountant_accounting you should add DISTINCT to SELECT statement to avoid duplicates.
For bob_sales_accounting bob will appear twice because it belongs to 2 groups.

Related

alias column names without mentioning column name

I'm trying to get all columns from each table with a prefix in the output, without mentioning all column names specifically in the select statement. Like:
SELECT *
FROM TABLE1 as T1
FULL JOIN TABLE2 as T2
ON T1.number=T2.number
Where I would want to get all column names from table1 and table2 prefixed with "T1" and "T2".
Many thanks in advance!
SELECT
CONCAT('T1', COLUMN_NAME), ORDINAL_POSITION
FROM
INFORMATION_SCHEMA.COLUMNS
WHERE
TABLE_NAME = 'TABLE1'
ORDER BY 2
UNION
SELECT CONCAT('T2', COLUMN_NAME), ORDINAL_POSITION
FROM
INFORMATION_SCHEMA.COLUMNS
WHERE
TABLE_NAME = 'TABLE2'
ORDER BY 2

Create dynamic SQL based on column names passed through a string

I need to find out rows that are present in table A and missing from table B (using LEFT JOIN) wherein table A and table B are two tables with same structure but within different schema.
But the query has to be constructed using Dynamic SQL and the columns that need to be used for performing JOIN are stored in a string. How to extract the column names from string and use them to dynamically construct below query :
Database is Azure SQL Server
eg :
DECLARE #ColNames NVARCHAR(150) = 'col1,col2'
Query to be constructed based on columns defined in ColNames :-
SELECT *
FROM Table A
Left Join
Table B
ON A.col1 = B.col1
AND A.col2 = B.col2
AND B.col1 IS NULL AND B.col2 IS NULL
If the number of columns in #ColNames is more then the SELECT statement needs to cater for all the column.
Without knowing the full context, try this:
DECLARE #ColNames NVARCHAR(150) = 'col1,col2'
DECLARE #JoinContion NVARCHAR(MAX) = ''
DECLARE #WhereCondition NVARCHAR(MAX) = ''
SELECT #JoinContion += CONCAT('[a].', QUOTENAME(Value), ' = ', '[b].', QUOTENAME(Value), (CASE WHEN LEAD(Value) OVER(ORDER BY Value) IS NOT NULL THEN ' AND ' ELSE '' END))
,#WhereCondition += CONCAT('[a].', QUOTENAME(Value), ' IS NULL', (CASE WHEN LEAD(Value) OVER(ORDER BY Value) IS NOT NULL THEN ' AND ' ELSE '' END))
FROM STRING_SPLIT(#ColNames,N',')
SELECT #JoinContion, #WhereCondition
String_Split: To split the input string into columns
Lead: to determine if we need the AND keyword when it's not the last row.
Be aware the NOT EXISTS is probably a better solution then LEFT JOIN

SQL Join based on three keys

Database is Teradata
I have two table which I am trying to join. Following are the table structures. When I join these table I expect to get two rows as output but getting 4 rows.what is reason for this behavior. Join based on three keys should uniquely identify a row but still getting 4 rows as output. Any help is appreciated.
TableA
Weekkey|segment|type|users
201501|1|A|100
201501|1|B|100
TableB
Weekkey|segment|type|revenue
201501|1|A|200
201501|1|B|200
when I join these two table using the following query i get the following result
select a.* ,b.user
from tablea a left join tableb b on a.weekkey=b.weekkey
and a.segment=b.segment
and a.type=b.type
Weekkey|segment|type|revenue|users
201501|1|A|200|100
201501|1|B|200|100
201501|1|A|200|100
201501|1|B|200|100
Using sql server, here is ddl and sample data along with the query you posted. The output you state you are getting doesn't happen here.
create table #tablea
(
Weekkey int
, segment int
, type char(1)
, users int
)
insert #tablea
select 201501, 1, 'A', 100 union all
select 201501, 1, 'B', 100
create table #TableB
(
Weekkey int
, segment int
, type char(1)
, revenue int
)
insert #TableB
select 201501, 1, 'A', 200 union all
select 201501, 1, 'B', 200
select a.*
, b.revenue
from #tablea a
left join #tableb b on a.weekkey = b.weekkey
and a.segment = b.segment
and a.type = b.type
drop table #tablea
drop table #TableB

Using UPPER in ON clause of JOIN for Postgres 9.2.4

When joining two tables on a varchar column wrapped in a upper statement, the join does not work if there is a trailing space in both of the varchar values.
In the two examples below, VALUE1 and VALUE2 = 'ABC '
-- Doesn't work
SELECT * FROM TABLE1 INNER JOIN TABLE2
ON UPPER(VALUE1) = UPPER(VALUE2)
-- Works
SELECT * FROM TABLE1 INNER JOIN TABLE2
ON UPPER(TRIM(VALUE1)) = UPPER(TRIM(VALUE2))
Has anyone else run into this problem?
Let's see:
CREATE TABLE table1(value1 varchar(10));
CREATE TABLE table2(value2 varchar(10));
INSERT INTO table1 values('ABC ');
INSERT INTO table2 values('ABC ');
SELECT * FROM TABLE1 INNER JOIN TABLE2
ON UPPER(VALUE1) = UPPER(VALUE2)
Result:
value1 | value2
--------+--------
ABC | ABC
It appears to work.
Make sure you don't use the CHAR(N) type instead of VARCHAR(N), since they have different semantics concerning spaces.

sqlite2: Joining max values per column from another table (subquery reference)?

I'm using the following database:
CREATE TABLE datas (d_id INTEGER PRIMARY KEY, name_id numeric, countdata numeric);
INSERT INTO datas VALUES(1,1,20); //(NULL,1,20);
INSERT INTO datas VALUES(2,1,47); //(NULL,1,47);
INSERT INTO datas VALUES(3,2,36); //(NULL,2,36);
INSERT INTO datas VALUES(4,2,58); //(NULL,2,58);
INSERT INTO datas VALUES(5,2,87); //(NULL,2,87);
CREATE TABLE names (n_id INTEGER PRIMARY KEY, name text);
INSERT INTO names VALUES(1,'nameA'); //(NULL,'nameA');
INSERT INTO names VALUES(2,'nameB'); //(NULL,'nameB');
What I would like to do, is to select all values (rows) of names - to which all columns of datas will be appended, for the row where datas.countdata is maximum for n_id (and of course, where name_id = n_id).
I can somewhat get there with the following query:
sqlite> .header ON
sqlite> SELECT * FROM names AS n1
LEFT OUTER JOIN (
SELECT d_id, name_id, countdata FROM datas AS d1
WHERE d1.countdata IN (
SELECT MAX(countdata) FROM datas
WHERE name_id=1
)
) AS p1 ON n_id=name_id;
n1.n_id|n1.name|p1.d_id|p1.name_id|p1.countdata
1|nameA|2|1|47
2|nameB|||
... however - obviously - it only works for a single row (the one explicitly set by name_id=1).
The problem is, the SQL query fails whenever I try to somehow reference the "current" n_id:
sqlite> SELECT * FROM names AS n1
LEFT OUTER JOIN (
SELECT d_id, name_id, countdata FROM datas AS d1
WHERE d1.countdata IN (
SELECT MAX(countdata) FROM datas
WHERE name_id=n1.n_id
)
) AS p1 ON n_id=name_id;
SQL error: no such column: n1.n_id
Is there any way of achieving what I want in Sqlite2??
Thanks in advance,
Cheers!
Oh, well - that wasn't trivial at all, but here is a solution:
sqlite> SELECT * FROM names AS n1
LEFT OUTER JOIN (
SELECT d1.*
FROM datas AS d1, (
SELECT max(countdata) as countdata,name_id
FROM datas
GROUP BY name_id
) AS ttemp
WHERE d1.name_id = ttemp.name_id AND d1.countdata = ttemp.countdata
) AS p1 ON n1.n_id=p1.name_id;
n1.n n1.name p1.d_id p1.name_id p1.countdata
---- ------------ ---------- ---------- -----------------------------------
1 nameA 2 1 47
2 nameB 5 2 87
Well, hope this ends up helping someone, :)
Cheers!
Notes: note that just calling max(countdata) screws up competely d_id:
sqlite> select d_id,name_id,max(countdata) as countdata from datas group by name_id;
d_id name_id countdata
---- ------------ ----------
3 2 87
1 1 47
so to get correct corresponding d_id, we must do max() on datas separately - and then perform sort of an intersect with the full datas (except that intersect in sqlite requires that there are equal number of columns in both datasets, which is not the case here - and even if we made it that way, as seen above d_id will be wrong, so intersect will not work).
One way to do that is in using a sort of a temporary table, and then utilize a multiple table SELECT query so as to set conditions between full datas and the subset returned via max(countdata), as shown below:
sqlite> CREATE TABLE ttemp AS SELECT max(countdata) as countdata,name_id FROM datas GROUP BY name_id;
sqlite> SELECT d1.*, ttemp.* FROM datas AS d1, ttemp WHERE d1.name_id = ttemp.name_id AND d1.countdata = ttemp.countdata;
d1.d d1.name_id d1.countda ttemp.coun ttemp.name_id
---- ------------ ---------- ---------- -----------------------------------
2 1 47 47 1
5 2 87 87 2
sqlite> DROP TABLE ttemp;
or, we can rewrite the above so a SELECT subquery (sub-select?) is used, like this:
sqlite> SELECT d1.* FROM datas AS d1, (SELECT max(countdata) as countdata,name_id FROM datas GROUP BY name_id) AS ttemp WHERE d1.name_id = ttemp.name_id AND d1.countdata = ttemp.countdata;
d1.d d1.name_id d1.countda
---- ------------ ----------
2 1 47
5 2 87

Resources