Combine data from dynamic table in SQL Server 2019 - sql

I have multiple tables more than 500 (maybe even more, we are creating them dynamically) with the same schema.
Tables are named CreateOrderRequestPending_TD001_%.
Is there any fast way to fetch data from all those tables?
I am trying to do this:
DECLARE #SQL NVARCHAR(MAX) = '';
DECLARE #TblName NVARCHAR(MAX);
DECLARE #I INT = 0;
DECLARE Tbl_Cursor CURSOR FOR
SELECT TABLE_NAME
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_CATALOG = 'z_scope'
AND TABLE_NAME LIKE 'CreateOrderRequestPending_TD001_%'
OPEN Tbl_Cursor
FETCH NEXT FROM Tbl_Cursor INTO #TblName
WHILE ##FETCH_STATUS = 0
BEGIN
IF #I > 0
SET #SQL += ' UNION ALL ';
SET #SQL += ' SELECT * FROM ' + #TblName + ' '
-- This query is more complex (having join with master table)
SET #I = #I + 1;
FETCH NEXT FROM Tbl_Cursor INTO #TblName
END
CLOSE Tbl_Cursor;
DEALLOCATE Tbl_Cursor;
EXEC(#SQL);

Issue
DROP VIEW COMBINED
;
CREATE VIEW COMBINED AS
SELECT * FROM ...
UNION ALL
SELECT * FROM ...
where you dynamically produce the list of constituent tables.
Then query the view.
From time to time the set of constituent tables will change.
Fortunately it is extremely fast to DROP / re- CREATE a VIEW.
Consider using dealer as a partition key,
so you have a single relation maintained by the backend (no VIEWs).
Then transactions for a given dealer would
all contend for locks on one of the underlying DB objects.

Related

Create an ms sql query to get data from tables belonging to different schemas

I have a table named 'tbl_user' and this table exists under many schemas for example :
schema1.tbl_user
schema2.tbl_user
and so on. I would like to union all the data in these tables and get a single result and I cannot use any programming language because the environment I need to run it doesn't allow for it. Is there a way to accomplish this on sql server 2008 using stored procedures?
Edit : There are over a thousand schemas and schemas can be added and deleted as time goes.
using cursor, create the query dynamic and execute at when completed.
You can add additional filter if you want to filter out the schema.
DECLARE #NAME VARCHAR(100)
DECLARE #SQL NVARCHAR(300)
DECLARE #TABLE_NAME NVARCHAR(300)='userMaster'
DECLARE CUR CURSOR FOR
SELECT S.name
from sys.schemas s
inner join sys.sysusers u
on u.uid = s.principal_id
order by s.name
OPEN CUR
FETCH NEXT FROM CUR INTO #NAME
WHILE ##FETCH_STATUS = 0
BEGIN
IF (EXISTS (SELECT *
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA =#NAME
AND TABLE_NAME =#TABLE_NAME))
BEGIN
IF(LEN(#SQL)>0)
begin
SET #SQL =#SQL+' UNION ALL SELECT * FROM ['+#NAME+'].['+#TABLE_NAME+']'
end
ELSE
begin
SET #SQL ='SELECT * FROM ['+#NAME+'].['+#TABLE_NAME+']'
end
--PRINT #SQL
END
FETCH NEXT FROM CUR INTO #NAME
END
CLOSE CUR
DEALLOCATE CUR
PRINT #SQL
exec(#SQL)
Try this and remember Tables should have the same structure.
SELECT *
FROM schema1.tbl_user
UNION
SELECT *
FROM schema2.tbl_user
And for large number of schemas you can use the following stored procedure. This will generate the UNION query dynamically and you can add the conditions to filter out the schema and table names.
DECLARE #table_name NVARCHAR(100)
DECLARE #schema_name NVARCHAR(100)
DECLARE #gettable CURSOR
DECLARE #query NVARCHAR(100)
SET #query=''
SET #gettable = CURSOR FOR
SELECT name,
schema_name(schema_id)
FROM sys.tables
OPEN #gettable
FETCH NEXT
FROM #gettable INTO #table_name, #schema_name
WHILE ##FETCH_STATUS = 0
BEGIN
SET #query = #query + 'SELECT * FROM ' + #schema_name + '.'+ #table_name + ' UNION ';
FETCH NEXT
FROM #gettable INTO #table_name, #schema_name
END
CLOSE #gettable
DEALLOCATE #gettable
print #query;

Information_schema.columns in the query

I need to pull the data from custom columns in all tables which have "custom1, custom2, custom3....." columns.
Declare #TableName varchar(max)
set #TableName = 'RandomTable';
with main as
(
select distinct
infos.COLUMN_NAME, infos.TABLE_NAME
from
INFORMATION_SCHEMA.COLUMNS infos
where
infos.TABLE_NAME = #TableName
and infos.COLUMN_NAME like 'Custom%%'
)
This query returns the list of custom columns in any table I specify in the parameter. Any idea how to use that in the query so I can get all the data from the RandomTable.Custom%% columns?
Any idea? I'm loosing the plot on it.
Following incomudro idea and guessing you are using SQL Server you could do something like this:
DECLARE
#TableName VARCHAR(MAX)
,#ColumnName VARCHAR(MAX)
,#SQLQuery VARCHAR(MAX)
,#FirstFlag BIT
SET #TableName = 'TEST'
SELECT
COL.COLUMN_NAME
INTO ##CUSTOM_COL
FROM INFORMATION_SCHEMA.COLUMNS COL
WHERE 1 = 1
AND COLUMN_NAME LIKE 'CUSTOM__'
AND TABLE_NAME = #TableName
DECLARE CUR_CUSTOM_COL CURSOR FOR
SELECT * FROM ##CUSTOM_COL
OPEN CUR_CUSTOM_COL
FETCH NEXT FROM CUR_CUSTOM_COL INTO #ColumnName
SET #FirstFlag = 1
SET #SQLQuery = 'SELECT *'
WHILE ##FETCH_STATUS = 0
BEGIN
IF #FirstFlag = 0
BEGIN
SET #SQLQuery = #SQLQuery + ', '
END
SET #SQLQuery = #SQLQuery + #ColumnName
SET #FirstFlag = 0
FETCH NEXT FROM CUR_CUSTOM_COL INTO #ColumnName
END
CLOSE CUR_CUSTOM_COL
DEALLOCATE CUR_CUSTOM_COL
SET #SQLQuery = #SQLQuery + ' FROM ' + #TableName
EXEC(#SQLQuery)
I saved my workspace in this fiddle. Unfortunaly it doesnt work there as intendet, but it should in your SQL Client(or I did a little typing mistake). With some little modifications you could not only display the custom columns from 1 specified table but from all tables. Also you could, besides selecting it, insert the ouput from the custom columns in temp tables.

Looping through a column in SQL table that contains names of other tables

I have fairly new to using SQL, currently I have a table that has a column that contains the names of all the tables I want to use for one query, so what I want to do is to loop through that column and go to every single one of these tables and then search one of their columns for a value (there could be multiple values), so whenever a table contains the value, I will list the name of the table. Could someone give me a hint of how this is done? Is cursor needed for this?
I don't have enough reputation to comment but is the table with the column that contain the table names all in one column, meaning that all the table names are comma separated or marked with some sort of separator? This would cause the query to be a little more complicated as you would have to take care of that before you start looping through your table.
However, this would require a cursor, as well as some dynamic sql.
I will give a basic example of how you can go about this.
declare #value varchar(50)
declare #tableName varchar(50)
declare #sqlstring nvarchar(100)
set #value = 'whateveryouwant'
declare #getTableName = cursor for
select tableName from TablewithTableNames
OPEN #getTableName
fetch NEXT
from #getTableName into #tableName
while ##FETCH_STATUS = 0
BEGIN
set #sqlstring = 'Select Count(*) from ' + #tableName + 'where ColumnNameYouwant = ' + #value
exec #sqlstring
If ##ROWcount > 0
insert into #temptable values (#tableName)
fetch next
from #getTableName into #tableName
END
select * from #temptable
drop table #temptable
close #getTableName
deallocate #getTableName
I'm currently not able to test this out as for time constraint reasons, but this is how I would go about doing this.
You could try something like this:
--Generate dynamic SQL
DECLARE #TablesToSearch TABLE (
TableName VARCHAR(50));
INSERT INTO #TablesToSearch VALUES ('invoiceTbl');
DECLARE #SQL TABLE (
RowNum INT,
SQLText VARCHAR(500));
INSERT INTO
#SQL
SELECT
ROW_NUMBER() OVER (ORDER BY ts.TableName) AS RowNum,
'SELECT * FROM ' + ts.TableName + ' WHERE ' + c.name + ' = 1;'
FROM
#TablesToSearch ts
INNER JOIN sys.tables t ON t.name = ts.TableName
INNER JOIN sys.columns c ON c.object_id = t.object_id;
--Now run the queries
DECLARE #Count INT;
SELECT #Count = COUNT(*) FROM #SQL;
WHILE #Count > 0
BEGIN
DECLARE #RowNum INT;
DECLARE #SQLText VARCHAR(500);
SELECT TOP 1 #RowNum = RowNum, #SQLText = SQLText FROM #SQL;
EXEC (#SQLText);
DELETE FROM #SQL WHERE RowNum = #RowNum;
SELECT #Count = COUNT(*) FROM #SQL;
END;
You would need to change the "1" I am using as an example to the value you are looking for and probably add a CONVERT/ CAST to make sure the column is the right data type?
You actually said that you wanted the name of the table, so you would need to change the SQL to:
'SELECT ''' + ts.TableName + ''' FROM ' + ts.TableName + ' WHERE ' + c.name + ' = 1;'
Another thought, it would probably be best to insert the results from this into a temporary table so you can dump out the results in one go at the end?

I have the same column in multiple tables, and want to update that column in all tables to a specific value. How can I do this?

The column is "CreatedDateTime" which is pretty self-explanatory. It tracks whatever time the record was commited. I need to update this value in over 100 tables and would rather have a cool SQL trick to do it in a couple lines rather than copy pasting 100 lines with the only difference being the table name.
Any help would be appreciated, having a hard time finding anything on updating columns across tables (which is weird and probably bad practice anyways, and I'm sorry for that).
Thanks!
EDIT: This post showed me how to get all the tables that have the column
I want to show all tables that have specified column name
if that's any help. It's a start for me anyways.
If that's a one time task, just run this query, copy & paste the result to query window and run it
Select 'UPDATE ' + TABLE_NAME + ' SET CreatedDateTime = ''<<New Value>>'' '
From INFORMATION_SCHEMA.COLUMNS
WHERE COLUMN_NAME = 'CreatedDateTime'
You could try using a cursor : like this
declare cur cursor for Select Table_Name From INFORMATION_SCHEMA.COLUMNS Where column_name = 'CreatedDateTime'
declare #tablename nvarchar(max)
declare #sqlstring nvarchar(max)
open cur
fetch next from cur into #tablename
while ##fetch_status=0
begin
--print #tablename
set #sqlstring = 'update ' + #tablename + ' set CreatedDateTime = getdate()'
exec sp_executesql #sqlstring
fetch next from cur into #tablename
end
close cur
deallocate cur
You can use the Information_Schema.Columns to build update scripts for you.
Declare #ColName as nVarchar(100), #NewValue as nVarchar(50)
Set #ColName = 'Modified' -- 'your col name'
Set #NewValue = '2013-11-04 15:22:31' -- your date time value
Select 'Update ' + TABLE_NAME + ' set ' + COLUMN_NAME + ' = ''' + #NewValue + '''' From INFORMATION_SCHEMA.COLUMNS Where column_name = 'modified'

Sql Server 2008 - How to query for status of fulltext catalogs on all user databases?

I have several databases in a Sql Server 2008 R2 instance. Some of those databases have a full-text enabled table. The name of the full-text table is equal for all databases, but the databases have different names and they are created on demand (I never know what databases exists and what does not).
The thing is: I need to query all catalogs in all databases to check if a population is done, but I have no idea how many databases I have (of course I know, but they are created on demand as I said). The script must query all databases and check if a population is done in a table (which the name I know because it never changes besides the name of the database that does change)
I have seen many people using things like:
sys.fulltext_catalogs
But it does not work if i am using the master database for example.
Any ideas?
Edit: Here is more complete code with a cursor, a full list of databases (even those without catalogs), and the right catalog view name:
SET NOCOUNT ON;
DECLARE #sql NVARCHAR(MAX) = N'';
SELECT #sql += ' UNION ALL
SELECT [name] = ''' + QUOTENAME(name) + ''',
catalog_name = name COLLATE Latin1_General_CI_AI,
is_importing
FROM ' + QUOTENAME(name) + '.sys.fulltext_catalogs'
FROM sys.databases WHERE database_id > 4;
SET #sql = 'SELECT [database] = d.name,
s.catalog_name,
s.is_importing
FROM sys.databases AS d
LEFT OUTER JOIN (' + STUFF(#sql, 1, 10, '') + ') AS s
ON QUOTENAME(d.name) = s.name
WHERE d.database_id > 4;';
CREATE TABLE #temp(db SYSNAME, catalog_name NVARCHAR(255), is_importing BIT);
INSERT #temp EXEC sp_executesql #sql;
DECLARE #db SYSNAME, #catalog_name NVARCHAR(255), #is_importing BIT;
DECLARE c CURSOR LOCAL STATIC FORWARD_ONLY READ_ONLY
FOR SELECT db, catalog_name, is_importing FROM #temp;
OPEN c;
FETCH NEXT FROM c INTO #db, #catalog_name, #is_importing;
WHILE ##FETCH_STATUS = 0
BEGIN
IF #catalog_name IS NULL
BEGIN
PRINT 'No catalogs for ' + #db;
END
ELSE
BEGIN
IF #is_importing = 1
BEGIN
PRINT 'Do something to ' + #db
+ '(importing)';
END
ELSE
BEGIN
PRINT #db + ' is not importing.';
END
END
FETCH NEXT FROM c INTO #db, #catalog_name, #is_importing;
END
CLOSE c;
DEALLOCATE c;
DROP TABLE #temp;
This gives you a complete list of used catalogs.
CREATE TABLE #info (
databasename VARCHAR(128)
, [Fulltext Catalog Name] VARCHAR(128));
SET NOCOUNT ON;
INSERT INTO #info
EXEC sp_MSforeachdb 'use ?
SELECT ''?''
, name
FROM sys.fulltext_catalogs;'
SELECT * FROM #info
-- get rid of temp table
DROP TABLE #info;