Dynamic SQL can make it? - sql

I have one table named AskLists with 2 fields :
AskListId AskInterview
2032 5
2032 3
2032 4
2032 6
5076 1
5076 3
5076 4
5076 5
5076 6
For each distinct number of the field AskListId, there is a table named by the number AskList'Number'
For example AskList5076 :
AskInterview QUOTA7
1 5660424
2 5660424
3 5660424
4 5667511
5 5667511
6 5667511
7 5667511
So there are hundred of tables AskList'Number'.
I am trying to add the field QUOTA7 which we can find in every AskList'Number' table to the main table AskLists.
For one table, it's easy :
SELECT AskListId
, AskInterview
,AskList5076.QUOTA7
FROM [Lists].[dbo].[AskLists]
INNER JOIN AskList5076 on AskLists.AskInterview = AskList5076.AskInterview
But I need to make it for all the values inside AskListId...
Is it possible to make it without making manually hundred of requests ?
I was told Dynamic SQL could make it but I don't know about it.

Have a look at the following and see if this works for you. It might require some slight tweaking and of course modifying to be an update, but in the context of your desired query shown above this should give you the values from each table.
declare #sql nvarchar(max)=''
select #sql +='
select al.AsklistId, al.AskInterview, aq.quota7
from lists.dbo.AskLists al join '
+ QuoteName(table_name)
+ ' on al.AskInterview=aq.AskInterview'
+ Iif(Count(*) over()=Row_Number() over(order by (select null)),'',' union all')
from INFORMATION_SCHEMA.COLUMNS
where table_name like 'Asklist%'
and table_name != 'Asklist'
and column_name='QUOTA7'
print #sql
-- exec sp_executesql #sql

You could use Dynamic SQL to union all your tables together before you join them.
Essentially putting them into the style of structure they should have been in in the first place
Something like this (it's more than a bit hacky)...
DECLARE #union NVARCHAR(MAX)
SELECT
#union =
STRING_AGG(
CAST(N'SELECT ''' + TABLE_NAME + N''' AS source_table, * FROM ' + TABLE_CATALOG + N'.' + TABLE_SCHEMA + N'.' + TABLE_NAME AS NVARCHAR(MAX)),
CHAR(13)+CHAR(10) + N'UNION ALL' + CHAR(13)+CHAR(10)
)
FROM
INFORMATION_SCHEMA.TABLES
WHERE
TABLE_NAME LIKE 'AskList%'
AND TABLE_NAME <> 'AskLists'
AND TABLE_CATALOG = 'Lists'
AND TABLE_SCHEMA = 'dbo'
;
DECLARE #sql NVARCHAR(MAX) = N'
WITH
unioned
AS
(
' + #union + '
)
SELECT
AskLists.AskListId
, AskLists.AskInterview
, unioned.QUOTA7
FROM
AskLists
INNER JOIN
unioned
on unioned.source_table = ''AskList'' + CAST(AskLists.AskListID AS VARCHAR(MAX))
and unioned.AskInterview = AskLists.AskInterview
'
EXEC sp_executesql #sql
Demo: db<>fiddle

Related

How to combine multiple results from a loop into one temp table

I have this statement:
Declare #sql varchar(max) = ''
declare #tablename as varchar(255) = 'test'
select #sql = #sql + 'select [' + c.name + '],count(*) as ''' + c.name
+ ''' from [' + t.name + ']'
from sys.columns c
inner join sys.tables t on c.object_id = t.object_id
where t.name = #tablename
EXEC (#sql)
But it gives the output comes out in different results windows and when I try to combine it with a union all the text doesn't fit it. I want to try and get the results into a temp table for SQL server is there anyway i can do this?
I'm trying to get:
Column Name Count Distinct Count
a 100 1
b 100 5
c 100 73
d 100 9
The statement above isn't for distinct count but i'm hoping I could replicate the same logic.
I suspect the query you want to construct really looks like:
select 'a' as column_name, count(column_name), count(distinct column_name)
from t
union all
select 'a' as column_name, count(column_name), count(distinct column_name)
from t
union all
. . .
To construct this in SQL Server, you can use logic like this:
declare #q nvarchar(max);
set #q = '
select ''[column_name]'' as column_name, count([column_name]) as cnt, count(distinct [column_name]) as distinct_count
from [table_name]
';
declare #sql nvarchar(max);
select #sql = string_agg(replace(replace(#q,
'[column_name]',
quotename(column_name)
),
'[table_name]',
quotename(table_name)
), ' union all '
)
from information_schema.columns c
where table_name = #name; -- should probably check the schema too!
exec sp_executesql #sql;

Find count of items from all tables in SQL Server database (filter tables based on column name)

I have to find the total number of distinct items from a particular column (named Ticker) from all tables in the database.
How can I achieve this?. This is what I want:
Table_name | Column | Total_Tickers
------------+---------+---------------
Table_1 | ticker | 500
Table_2 | ticker | 100
Table_3 | ticker | 5000
.
.
I know I've got to use sp_MSForEachTable but I'm not sure how to filter those tables that do not have a Ticker column at all.
This is what I've tried:
create table #counts
(
table_name varchar(255),
ticker_count int
)
EXEC sp_MSForEachTable #command1='INSERT #counts (table_name, ticker_count)
SELECT ''?'', COUNT(ticker) FROM ? ',
#whereand = 'AND ''?'' IN (Select * from information_schema.columns where
column_name = ''%ticker%'')'
SELECT table_name, ticker_count
FROM #counts
ORDER BY table_name, ticker_count DESC
DROP TABLE #counts
It doesn't recognize the COUNT(ticker) on the 7th line since I'm not able to filter the tables!
I'd appreciate any pointers on this. Thanks
Here is a much easier approach
use your_databasename --replace with your database name
go
DECLARE #sql VARCHAR(max)= '',
#column_name SYSNAME = 'ticker'
SET #sql = Stuff((SELECT ' union all select Table_name = '''+ table_name + ''',[Column] = ''' + column_name
+ ''',Total_Tickers = count(distinct '+ column_name + ') from '
+ Quotename(table_catalog) + '.'+ Quotename(table_schema) + '.'+ Quotename(table_name)
FROM information_schema.columns
WHERE column_name = #column_name
FOR xml path('')), 1, 11, '') -- stuff is used to remove the first union all
--SELECT #sql
EXEC (#sql)
Since tables has to be filtered based on column name, I don't think msforeachtable would be helpful here.

Resultset from Facts across different schemas

We have a DB which has several schemas and each schema has a Fact table. I need to prepare a result set with schema name, max(MTH_DT) from Fact and distinct MTH_DT counts from each Fact table.
SCHEMA_NAME MAX(MTH_DT) DISTINCT_COUNT(MTH_DT)
SCHM_1 11/30/2015 24
SCHM_2 10/31/2015 24
SCHM_3 11/30/2015 36
SCHM_4 10/31/2015 24
SCHM_5 11/30/2015 24
How can I get the resultset in this fashion?
Here it goes
Just uncomment the EXECUTE statement when you are sure of the query and run the query:
DECLARE #SQL VARCHAR(MAX) = ''
SELECT #SQL += 'SELECT '''+T.TABLE_NAME+''' AS [SCHEMA_NAME],MAX(MTH_DT) AS [MAX(MTH_DT)] ,COUNT(MTH_DT) AS [DISTINCT_COUNT(MTH_DT)] FROM '+T.TABLE_SCHEMA+'.'+T.TABLE_NAME + ' UNION ' FROM INFORMATION_SCHEMA.TABLES AS T WHERE T.TABLE_NAME like 'SCHM_%'
SELECT #SQL = SUBSTRING(#SQL,1,LEN(#SQL) - LEN('UNION'))
PRINT (#SQL)
--EXECUTE (#SQL)
Here is a safer way to build your dynamic sql than using INFORMATION_SCHEMA.TABLES. I left off the group by because it is a constant so you don't actually need a group by.
declare #SQL nvarchar(MAX) = ''
select #SQL = #SQL + 'select ''' + name + ''' as SchemaName, MAX(MTH_DT) as MaxMTH_DT, COUNT(distinct MTH_DT) as DISTINCT_COUNT_MTH_DT from ' + name + '.Fact union all '
from sys.schemas
where SCHEMA_ID > 4
and SCHEMA_ID < 16384
Select #SQL = LEFT(#SQL, LEN(#SQL) - 9) + ' order by SchemaName'
select #SQL

SQL distinct and count for a column in multiple tables

So what I want is to have a table of distinct values and the count for those values. basically I want it to look like this:
DistinctValue | Count
Bob | 4
Fred | 5
George | 2
Joeseph | 1
for a single table I use :
SELECT ColumnName, COUNT(*) from TableName group by Column
How would I do this so that it would span across multiple tables. I have about say 30, possibly more, tables I need to do this for.
Any help would be greatly appreciated. Let me know if there's more information you need. Oh, and there's no worry about the column name because all the tables have the same column name.
WITH mytbl AS (
SELECT ColumnName, COUNT(*) AS myCount from TableName group by Column
UNION ALL
SELECT ColumnName, COUNT(*) from TableName2 group by Column
... a union all for every table
)
SELECT ColumnName, SUM(myCount)
FROM mytbl
GROUP BY ColumnName
-- If you are using an earlier version of MS SQL, the UNION statements can be put in a big sub select or a table variable.
-- IE, they'd take the place of mytbl in the last query replace mytbl in the bottom query with the UNIONS from the CTE
SELECT
t.name,
count(c.name) as columnsname
FROM
sys.tables t
inner join sys.columns c
ON t.object_id = c.object_id
group by t.name
You'll need to create and execute dynamic tsql to get your results:
DECLARE #Tsql NVARCHAR(MAX) = ''
DECLARE #ColumnName SYSNAME = 'YourColumnName'
SELECT #Tsql = #Tsql + 'SELECT ''[' + c.TABLE_SCHEMA + '].[' + c.TABLE_NAME + ']'' AS TableName, ' +
'[' + #ColumnName + '], COUNT(*) AS RecordCount FROM [' + c.TABLE_SCHEMA + '].[' + c.TABLE_NAME + '] GROUP BY [' + #ColumnName + '] UNION ' + CHAR(13) + CHAR(10)
FROM INFORMATION_SCHEMA.COLUMNS c
JOIN INFORMATION_SCHEMA.TABLES t
ON t.TABLE_SCHEMA = c.TABLE_SCHEMA
AND t.TABLE_NAME = c.TABLE_NAME
--Comment out the next line if you want data/counts for views too.
AND t.TABLE_TYPE = 'BASE TABLE'
WHERE c.COLUMN_NAME = #ColumnName
--Remove the last UNION (and carriage-return, line-feed)
SELECT #Tsql = LEFT(#Tsql, LEN(#Tsql) - 8)
--Verify query.
PRINT #Tsql
--Uncomment when ready to proceed.
--EXEC (#Tsql)

SQL Select tables / list tables

I would like to ask for help.
As I have 500 plus tables, and I need to search those table's column having some similar words. Is it possible to search and list those tables?
E.g
Table 1 - Name, age, height
Table 2 - Result, Name, Score
Table 3 - Name, Pic, Parent1, Parent2
I wan to do a query to select all the table that any of the column contain the word "%Name%", is this possible?
Just run following query in your db and replace your search string with string and it will work.
SQL for find particular word/value from all columns and tables in a database
DECLARE #SQL VARCHAR(MAX)
DECLARE #valueToFind VARCHAR(1000)
DECLARE #columnName VARCHAR(1000)
SET #valueToFind = 'string'
SET #columnName = '%%'
CREATE TABLE #TMP
(Clmn VARCHAR(500),
CNT INT)
SELECT #SQL=COALESCE(#SQL,'')+CAST('INSERT INTO #TMP Select ''' + TABLE_SCHEMA + '.' + TABLE_NAME + '.' + COLUMN_NAME + ''' AS Clmn, count(*) CNT FROM '
+ TABLE_SCHEMA + '.[' + TABLE_NAME +
'] WHERE [' + COLUMN_NAME + '] LIKE ''%' + #valueToFind + '%'' ;' AS VARCHAR(8000))
FROM INFORMATION_SCHEMA.COLUMNS
JOIN sysobjects B
ON INFORMATION_SCHEMA.COLUMNS.TABLE_NAME = B.NAME
WHERE COLUMN_NAME LIKE #columnName AND xtype = 'U'
AND DATA_TYPE IN ('char','nchar','ntext','nvarchar','text','varchar')
--PRINT (#SQL)
EXEC(#SQL)
SELECT * FROM #TMP WHERE CNT > 0
DROP TABLE #TMP
-----------------------------------------------------------------------------------------