Combining multiple tables in SQL - sql

I need a result set of multiple tables combined.
I have a query with a from clause using a table for each country that are selected in the parameter.
Ex:
#prmCountry='AU,UK,US'
Now in the from clause the table name is as such that it has to run for each country separately:
from tbl_abc t1
left outer join tbl_country_(CountryName) t2
on.....
How to exactly do this?

As your question is not more clear, but you are looking in some dynamic SQL Query :
DECLARE #prmCountry VARCHAR(MAX)= 'AU,UK,US';
DECLARE #SQL NVARCHAR(MAX)= N'';
DECLARE #Query NVARCHAR(MAX);
SELECT #SQL+=N' left join table_'+CC.Country+' on table_'+CC.Country+'.<column> = t1.<column>'
FROM
(
SELECT split.a.value('.', 'NVARCHAR(MAX)') [Country]
FROM
(
SELECT CAST('<A>'+REPLACE(#prmCountry, ',', '</A><A>')+'</A>' AS XML) AS Country
) C
CROSS APPLY Country.nodes('/A') AS split(a)
) CC;
SET #Query = 'SELECT * FROM tbl_abc t1'+#SQL+';';
PRINT #Query;
--EXECUTE sp_executesql #query
SQL Query produce :
SELECT * FROM tbl_abc t1
left join table_AU on table_AU.<column> = t1.<column>
left join table_UK on table_UK.<column> = t1.<column>
left join table_US on table_US.<column> = t1.<column>;
In above, first Splited the #prmCountry values into rows form.
Create dynamic left join query with#prmCountry values

Use UNION ALL like this:
SELECT
tbl_abc t1
left outer join tbl_country_('AU') t2
on.....
UNION ALL
SELECT
tbl_abc t1
left outer join tbl_country_('US') t2
on.....
...and so on

Related

Pull Table Information from code

I have a table in SQL Server 2012 with 3 columns:
RDDID, SPDESC, SQLTEXT
Column SQLTEXT contains inline queries.
Is it possible to extract all table names from SQLTEXT and put them into a separate column?
INPUT:
RDDID|SPDESC|SQLTEXT
10XH1|DAGASC|SELECT COL1 FROM TABLE1 AS A JOIN TABLE2 B ON A.ID=B.ID JOIN TABLE3 AS C ON A.ID=C.ID
OUTPUT
RDDID|SPDESC|COLX1|COLX2|COLX3|
10XH1|DAGASC|TABLE1|TABLE2|TABLE3
Please share your thoughts.
If you could TRY Regex or any simple technique to split the line with delimiter[space],
You could try the following:
declare #query varchar(1000) = 'SELECT COL1 FROM TABLE1 AS A JOIN TABLE2 B ON A.ID=B.ID JOIN TABLE3 AS C ON A.ID=C.ID'
select b.name, 'ColX'+ cast(row_number() over( order by (select 0)) as varchar) as rn into #temp
from dbo.RegExSplit(' ',#query,1) a join sys.tables b on a.match = b.name
declare #cols varchar(100)
select #cols =
stuff((select ',' +rn from #temp for xml path('')),1,1,'')
exec('select * from #temp pivot(max(name) for rn in ('+#cols+' ))piv')
drop table #temp

Can we use LIKE in subquery instead of IN

I am using following sql query
SELECT * FROM TestTable WHERE keyword IN ( Select Tags from Tags)
keyword in table are stored as keyword1, keyword2, keyword3
If it was single keyword the above query works fine but i have multiple keywords and i need to search each one of them in the
I dont thing above query is giving me right result as i am comparing
keyword1, keyword2, keyword3 with IN (keyword1, keyword2, keyword3) which wont match i tried o use instead
SELECT * FROM TestTable WHERE keyword LIKE ( Select Tags from Tags)
But it generates error
Subquery returned more than 1 value. This is not permitted when the
subquery follows =, !=, <, <= , >, >= or when the subquery is used as
an expression. The statement has been terminated.
can can i make it work so it loops through each keyword in table1, Table2 is tempTable and has these keyword1, keyword2, keyword3 in three rows
SQL FIDDLE
Fiddle is with sample data
You can do like following if you want to use pattern match.
Using EXISTS
SELECT * FROM TABLE1 T1
WHERE EXISTS
(
SELECT 1 FROM TABLE2 T2 WHERE T1.Keyword LIKE '%' + T2.keyword + '%'
)
Using JOIN
SELECT * FROM TABLE1 T1
INNER JOIN TABLE2 T2 ON T1.Keyword LIKE '%' + T2.keyword + '%'
If it is exact match, you ca do like following.
SELECT * FROM TABLE1 T1
INNER JOIN TABLE2 T2 ON T1.Keyword = T2.keyword
About your error:
Your subquery gives you multiple results and the LIKE operator cant compare more then 1 to 1. The IN operator was a good idea, but
If you are looking for something in table2 that matches EXACTLY a record (or more) in table1 this is your target:
SELECT *
FROM TABLE1
INNER JOIN TABLE2 ON TABLE2.keyword = TABLE1.keyword
If you are looking for anything in table2 that is SIMILAR to one or more records to the table1 use this:
SELECT *
FROM TABLE1
INNER JOIN TABLE2 ON TABLE2.keyword+'%' LIKE TABLE1.keyword
if you are on sql server or +, use string_split function, else :
create function split:
CREATE FUNCTION [dbo].[fn_split](
#str VARCHAR(MAX),
#delimiter CHAR(1)
)
RETURNS #returnTable TABLE (idx INT PRIMARY KEY IDENTITY, item VARCHAR(8000))
AS
BEGIN
DECLARE #pos INT
SELECT #str = #str + #delimiter
WHILE LEN(#str) > 0
BEGIN
SELECT #pos = CHARINDEX(#delimiter,#str)
IF #pos = 1
INSERT #returnTable (item)
VALUES (NULL)
ELSE
INSERT #returnTable (item)
VALUES (rtrim(ltrim(SUBSTRING(#str, 1, #pos-1))))
SELECT #str = SUBSTRING(#str, #pos+1, LEN(#str)-#pos)
END
RETURN
END
Split your values like it:
select * from tmp20180308 t1 CROSS APPLY fn_split(t1.keyword, ',') t2
inner join table2 t3 on t3.keyword=t2.item
and do your joins with other table
It can be done using Dynamic SQL. Check different methods for the one that has performance advantage:
SQLFiddle:
Declare #keywords as nvarchar(max)
Declare #Sql as nvarchar(max)
select #keywords =
stuff((
select distinct ' or [Tags] like ''%' + [tags] + '%'''
from [tags]
for xml path('')
),1,3,'')
set #Sql = 'SELECT * FROM [TestTable] WHERE ' + #keywords
exec(#Sql)
Not Fiddle:
create table a (keyword varchar(20))
create table b (keyword varchar(20))
insert into a values ('the'), ( 'quick'), ( 'brown'), ( 'fox'), ( 'jumped'), ( 'over'), ( 'the'), ( 'lazy'), ( 'dog')
insert into b values ('the'), ( 'quic'), ( 'browns'), ( 'x'), ( 'jumped'), ('quick,brown,fox')
Declare #keywords as nvarchar(max)
Declare #Sql as nvarchar(max)
select #keywords =
stuff((
select distinct ' or keyword like ''%' + [keyword] + '%'''
--select distinct ' or keyword = ''' + [keyword] + '''' --if exact match is required
from b
for xml path('')
),1,3,'')
set #Sql = 'SELECT * FROM a WHERE ' + #keywords
exec(#Sql)

SQL Server dynamic table

I have 3 tables and I want to return result as one dynamic table, and use it with an ASP.NET GridView. However when I run my query I get a syntax error:
Declare #AghlamTitle_Topic nvarchar(max)
Declare #query nvarchar(max)
Select
#AghlamTitle_Topic =
stuff((select distinct ','+QuoteName([TopicTitle])
from Tbl_Topic
where Topic_PID = 29
for xml path('')), 1, 1, '')
Set #Query = ' Select *
From (Select
t2.Aghlam_Marasemat_PID,
View_Marasem_ALL.MarasemID ,
t2.[AghlamDateReg],
t1.[TopicTitle],
t2.AghlamCount
from
Tbl_Aghlam_Num t2 View_Marasem_ALL
inner join
Tbl_Topic t1
pivot (max([AghlamCount]) for [TopicTitle] in ( ' +#AghlamTitle_Topic + ' ) ) p
inner join t2 on View_Marasem_ALL.MarasemID = t2.Aghlam_Marasemat_PID'
exec sp_executeSql #query
Does someone have a solution?
Tbl_Aghlam_Num t2 View_Marasem_ALL
This is a syntax error. You have a Table name followed by the alias name t2 followed by View_Marasem_ALL, whatever that is.
If you need to also join to View_Marasem_ALL, then you need to add an additional JOIN clause.

Change Rows to Columns in SQL Server

I've been working on this query for an hour and half but I can't get it done,
First, this is my query:
SELECT
Questions, PossibleAnswer,
((COUNT(PossibleAnswer) + 0.0) / 10 ) * 100 AS Percentage
FROM
(SELECT
A.AnswerID, B.Questions, B.QuestionID, C.PossibleAnswer
FROM
TblSurveyCustomerAnswers A
INNER JOIN
TblSurveyQuestion B ON A.QuestionID = B.QuestionID
INNER JOIN
TblSurveyAnswer C ON A.AnswerID = C.AnswerID
WHERE
A.CustomerID = 1) AS SOURCE
GROUP BY
Questions, PossibleAnswer
The result is below:
Now, I want the rows for column name PossibleAnswer to be converted in columns, so I did a research and found the PIVOT command (I need dynamic since it's a possible answers field) and this is my code
DECLARE #DynamicPivotQuery AS NVARCHAR(MAX)
DECLARE #ColumnName AS NVARCHAR(MAX)
--Get distinct values of the PIVOT Column
SELECT #ColumnName= ISNULL(#ColumnName + ',','')
+ QUOTENAME(PossibleAnswer)
FROM
(
SELECT DISTINCT X.*
FROM
(
SELECT Questions,PossibleAnswer, ((COUNT(PossibleAnswer) + 0.0) / 10 ) * 100 AS Percentage
FROM
(
SELECT A.AnswerID,B.Questions, B.QuestionID, C.PossibleAnswer
FROM TblSurveyCustomerAnswers A
INNER JOIN TblSurveyQuestion B
ON A.QuestionID = B.QuestionID
INNER JOIN TblSurveyAnswer C
ON A.AnswerID = C.AnswerID
WHERE A.CustomerID = 1
) AS SOURCE
GROUP BY Questions, PossibleAnswer
) X
) AS B
--Prepare the PIVOT query using the dynamic
SET #DynamicPivotQuery =
'SELECT Questions, ' + #ColumnName + '
FROM TblSurveyCustomerAnswers A
INNER JOIN TblSurveyQuestion B
ON A.QuestionID = B.QuestionID
PIVOT(Max(Questions)
FOR PossibleAnswer IN (' + #ColumnName + ')) AS PVTTable'
--Execute the Dynamic Pivot Query
EXEC sp_executesql #DynamicPivotQuery
And I can't get the pivot work, need help. I'm stuck. See this error:
In general for questions like these you should provide sample data, table definitions and expected output so people can take your script, fiddle with it and produce something that works. See How to post a T-SQL question on a public forum for one way to do this.
Since it is hard to look at a dynamic script, not having the table structures, and point at what your problem is, let me give you the following advice:
Instead of taking your big query that produces the output and form queries around that big query, first insert the output of that query into a temporary table. You can do this by placing an INTO #temp_table clause after the SELECT clause. This creates a new temporary table #temp_table containing the output of the query.
SELECT --your select columns
INTO #p_in -- creates a temporary table #p_in that contains the output
FROM --the rest of your query
Determine the pivot columns based on the newly created temporary table. It'll be a lot more conscise and easier to spot errors
Write your Dynamic SQL using the temporary table (again it'll be a lot more conscise and easier to spot errors)
Don't forget to DROP the temporary table after executing the dynamic SQL.
I just try to solved problem without temporary table. You may edit query as your requirement.
--For PIVOT column
DECLARE #ColumnName AS NVARCHAR(MAX)
SELECT #ColumnName ''''+ PossibleAnswer + '''' + ' , ' + #ColumnName
FROM
(
SELECT
DISTINCT PossibleAnswer
FROM
(
SELECT
A.AnswerID, B.Questions, B.QuestionID, C.PossibleAnswer
FROM
TblSurveyCustomerAnswers A
INNER JOIN
TblSurveyQuestion B ON A.QuestionID = B.QuestionID
INNER JOIN
TblSurveyAnswer C ON A.AnswerID = C.AnswerID
WHERE
A.CustomerID = 1
) AS SOURCE
)B
--For removing last comma
IF #ColumnName != ''
BEGIN
SET #ColumnName = SUBSTRING(#ColumnName, 1, LEN(#ColumnName)-1)
END
-- Make result
SELECT *
FROM
(
SELECT Questions,PossibleAnswer, ((COUNT(PossibleAnswer) + 0.0) / 10 ) * 100 AS Percentage
FROM
(
SELECT A.AnswerID,B.Questions, B.QuestionID, C.PossibleAnswer
FROM TblSurveyCustomerAnswers A
INNER JOIN TblSurveyQuestion B
ON A.QuestionID = B.QuestionID
INNER JOIN TblSurveyAnswer C
ON A.AnswerID = C.AnswerID
WHERE A.CustomerID = 1
) AS SOURCE
GROUP BY Questions, PossibleAnswer
)C
PIVOT
( Max(Questions)
FOR PossibleAnswer IN (#ColumnName)
) AS PVTTable

Generic code to determine how many rows from a table are in a different table with matching structure?

How can I create a generic function in C# (LINQ-to-SQL) or SQL that takes two tables with matching structure and counts how many rows in TableA that are in TableB.
TableA Structure
Value1, Value2
TableA Data
1,1
TableB Structure
Value1, Value2
TableB Data
1,1,
1,2
To get count of matching rows between TableA and TableB:
SELECT COUNT(*) FROM TableA
INNER JOIN TableB ON
TableA.Value1 = TableB.Value1 AND
TableA.Value2 = TableB.Value2
The result in this example
1
So the query above works great, but I don't want to have to write a version of it for every pair of tables I want to do this for since the INNER JOIN is on every field. I feel like there should be a more generic way to do this instead having to manually type out all of the join conditions. Thoughts?
Edit: Actually, I think I'll need a C#/LINQ answer since this will be done across servers. Again, this is annoying because I have to write the code to compare each field manually.
var tableARows = dbA.TableA.ToList();
var tableBRows = dbB.TableB.ToList();
var match = 0;
foreach(tableARow in tableARows){
if(tableBRows.Where(a=>a.Value1 = tableARow.Value1 && a.Value2 = tableARow.Value2).Any()){
match++;
}
}
return match;
using sql server this will work
var sql="select count(0) from(
select * from product except select * from product1
) as aa";
dc = dtataContext
var match= dc.ExecuteStoreQuery<int>(sql);
You could generate the join using syscolumns.
declare #tablenameA varchar(50) = 'tableA'
declare #tablenameB varchar(50) = 'tableB'
declare #sql nvarchar(4000)
select #sql =''
select #sql = #sql + ' and ' + quotename(#tablenameA )+ '.'
+ c.name +' = ' + quotename(#tablenameB )+ '.' + c.name
from syscolumns c
inner join sysobjects o on c.id = o.id
where o.name = #tablenameA
select #sql = 'select count(*) from ' + #tablenameA + ' inner join '+#tablenameB+' on '
+ substring (#sql, 5, len(#sql))
exec sp_executesql #sql
You query the ANSI INFORMATION_SCHEMA views, thus:
select *
from INFORMATION_SCHEMA.COLUMNS col
where col.TABLE_SCHEMA = <your-schema-name-here>
and col.TABLE_NAME = <your-table-name-here>
order by col.ORDINAL_POSITION
against each of the tables involved. The result set will provide everything needed for your to construct the required query on the fly.
One fairly simple answer:
select ( select count(*) from
(select * from TableA UNION ALL select * from TableB) a ) -
( select count(*) from
(select * from TableA UNION select * from TableB) d ) duplicates