SQL - Get rows from all tables where a common column is null - sql

I need to find all of the rows in any table where the create/update date are null
There are over 500 tables so doing something like the following is not feasible.
SELECT *
FROM
(SELECT
'tableA' AS `table`,
IF(COUNT(`column_a`), NULL, 'column_a') AS `column`
FROM tableA
UNION ALL
SELECT
'tableB' AS `table`,
IF(COUNT(`column_b`), NULL, 'column_b') AS `column`
FROM tableB
UNION ALL
-- etc.
) t
WHERE
`column` IS NOT NULL
I figured I could use INFORMATION_SCHEMA somehow but I am having difficulty with that.

I generally do this by using sys.tables to populate a list of the tables into a temp table, then compose dynamic SQL around that list.
select quotename( schemas.name ) + '.' + quotename(tables.name) as tbl
into #work
from sys.tables
join sys.schemas on tables.schema_id = schemas.schema_id
select
'select ''' + tbl + ''' as [table] where exists ( select * from ' + tbl + ' where column_a is null )' as sqlcmd,
'select ''' + tbl + ''' as [table], * from ' + tbl + ' where createdate is null ' as sqlcmd
from #work
drop table #work
Once you have the list you can execute it manually in SSMS or iterate through it using a cursor to execut each statement. The quotation marks can give you a headache, though. Dynamic SQL isn't for the faint of heart.

Related

Update columns in multiple tables by names pulled from a temporary table

I have a temp table where various table names and connected column names are stored. If I were to run a simple SELECT on it the results would look something like this:
----------------
TableName | ColumnName
------------------
Users | RoleId
Tables | OwnerId
Chairs | MakerId
etc...
I'm looking for a way to set mentioned column values in the connected tables to NULL.
I know how to do it via a CURSOR or a WHILE loop by processing each row individually but I'm trying to eliminate these performance hoarders from my stored procedures.
Is there any way to build a join by table names from the TableName column to the actual tables to then set connected ColumnName column values to NULL ?
Check this Script-
IF OBJECT_ID('SampleTable') IS NOT NULL
DROP TABLE SampleTable
CREATE TABLE SampleTable
(
Table_Name VARCHAR(50) NOT NULL,
Column_Name VARCHAR(50) NOT NULL
)
GO
INSERT INTO SampleTable
VALUES
('Users','RoleId'),('Tables','OwnerId'),('Chairs','MakerId') --Give your Combo here
GO
--Check this scripts
SELECT 'UPDATE ' + QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(S1.TABLE_NAME) +
' SET ' + QUOTENAME(S1.COLUMN_NAME) + ' = NULL ; '
AS [Dynamic_Scripts]
FROM SampleTable S JOIN INFORMATION_SCHEMA.COLUMNS S1 ON s.Table_Name=s1.Table_Name and s.Column_Name=s1.Column_Name
--Check this scripts (multiple column single script; 1 table 'n' column - 1 update query)
SELECT 'UPDATE ' + CONCAT('[',TABLE_SCHEMA,'].[',S1.TABLE_NAME,'] SET ') + STRING_AGG(CONCAT('[',S1.COLUMN_NAME,']=NULL'),',') + ' ; ' AS [Dynamic_Scripts]
FROM SampleTable S JOIN INFORMATION_SCHEMA.COLUMNS S1 ON s.Table_Name=s1.Table_Name and s.Column_Name=s1.Column_Name
GROUP BY CONCAT('[',TABLE_SCHEMA,'].[',S1.TABLE_NAME,'] SET ')
Try this,
IF OBJECT_ID('SampleTable') IS NOT NULL
DROP TABLE SampleTable
CREATE TABLE SampleTable
(
Table_Name VARCHAR(50) NOT NULL,
Column_Name VARCHAR(50) NOT NULL
)
GO
INSERT INTO SampleTable
VALUES
('Users','RoleId'),('Tables','OwnerId'),('Chairs','MakerId')
,('Users','Appid'),('Tables','Column') --Give your Combo here
GO
declare #Sql nvarchar(1000)=''
;with CTE as
(
select QUOTENAME(a.Table_Name)Table_Name
,stuff((select ','+QUOTENAME(Column_Name),'=null'
from SampleTable B
where a.Table_Name=b.Table_Name for xml path('') ),1,1,'')UpdateCol
from SampleTable A
group by a.Table_Name
)
select #Sql=coalesce(#Sql+char(13)+char(10)+SingleUpdate,SingleUpdate)
from
(
select CONCAT('Update ',Table_Name,' ','SET ',UpdateCol)SingleUpdate
from cte
)t4
print #Sql
select #Sql
Execute sp_executeSql #Sql

INNER JOIN with ON All columns except one Column

I have 2 tables(Table1 and Table2). Both tables schema are exactly the same and both might have duplicated set of records except IDs since ID is auto generated.
I would like to get the common set of records but with ID to follow as Table1's ID. So, I query using Inner join. It works as I expected.
SELECT Table1.ID, Table1.Param1, Table1.Param2, Table1.Param3
INTO #Common
FROM Table1
INNER JOIN Table2 ON Table1.Param1 = Table2.Param1
AND Table1.Param2 = Table2.Param2
AND Table1.Param3 = Table2.Param3
However, in actual usage, the total number of parameters in both tables will be around 100. So, the total number of comparison inside ON clause will increase up to 100.
How can I do inner join by excluding one column instead of comparing all columns in ON clause?
By removing ID column from both tables and doing intersect also no possible since I still want to extract Table1 ID for other purpose.
I can achieve the common of 2 table by removing ID and compare those 2 table.
However, that still do not serve my requirement, since I need to get Table1 ID for those common data.
SELECT * INTO #TemporaryTable1 FROM Table1
ALTER TABLE #TemporaryTable1 DROP COLUMN ID
SELECT * INTO #TemporaryTable2 FROM Table2
ALTER TABLE #TemporaryTable2 DROP COLUMN ID
SELECT * INTO #Common FROM (SELECT * FROM #TemporaryTable1 INTERSECT SELECT * FROM #TemporaryTable2) data
SELECT * FROM #Common
If i understood your problem correctly i guess you could generate dynamically the query you want to use using the following code :
DECLARE #SQL nvarchar(max) = 'SELECT ',
#TBL1 nvarchar(50) = 'data',
#TBL2 nvarchar(50) = 'data1',
#EXCLUDEDCOLUMNS nvarchar(100)= 'ID,col1'
-- column selection
SELECT #sql += #tbl1 + '.' + COLUMN_NAME + ' ,
'
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = #TBL1
-- from clause and remove last ,
set #SQL = LEFT(#sql,LEN(#sql) - 5)
SET #sql += '
FROM ' + #TBL1 + ' INNER JOIN
' + #TBL2 + '
ON '
-- define the on clause
SELECt #SQL += #tbl1 + '.' + COLUMN_NAME + ' = '+ #tbl2 + '.' + COLUMN_NAME +',
'
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = #TBL1
AND COLUMN_NAME not in (#EXCLUDEDCOLUMNS)
--remove last ,
set #SQL = LEFT(#sql,LEN(#sql) - 3)
--SELECt #SQL
EXEC SP_EXECUTESQL #sql
Before you execute make sure the #sql is properly generated. choose the columns you want to exclude from your on clause using the #EXCLUDEDCOLUMNS parameter.

Create Sql Server view using table name from sysobjects table

I have around 200 tables. I want to create a view from all these tables. I feel it is inefficient to hardcode all the table names and do an UNION ALL in the view definition.
Instead I am planning to retrieve the table name from sysobjects table like
Select name from sysobjects where name like 'Warehouse_Inventory%'
How can I use these table names and create a view out of it?
Note: I am selecting only 10 columns which are common. If any column is not present in a table, I want to display NULL for it.
This Query may help you..
SELECT 'CREATE VIEW VIEW_NAME AS'
UNION ALL
SELECT 'SELECT * FROM ['+NAME+']
UNION ALL' FROM SYS.TABLES where name like 'Warehouse_Inventory%'
I am not sure why you want to use sys.sysojects instead of other sys views. Also now sure why when you want to union all tables you would want to search by a table name..... I would probably recommend a cursor on tables and temp tables to hold your results if you have 200 tables just do to size of the query but if you really really want to do it via union all here is a way...
Build a list of the 10 columns you want. Then run the query. you may need to tweak and add some cast/convert function to ensure everything is the right datatypes this can be done dynamically with sys.types and sys.columns or just make sure everything is a NVARCHAR(???) by altering my dynamic sql below and move forward.
DECLARE #ListOfColumns AS TABLE (ColumnName VARCHAR(100))
INSERT INTO #ListOfColumns (ColumnName) VALUES ('col1'),('col2'),('col3')
DECLARE #SQLStatement NVARCHAR(MAX)
;WITH cteColumnsTableCross AS (
SELECT
SchemaName = s.name
,t.schema_id
,TableName = t.name
,l.ColumnName
FROm
#ListOfColumns l
CROSS JOIN sys.tables t
INNER JOIN sys.schemas s
ON t.schema_id = s.schema_id
)
, cteColumns AS (
SELECT
x.SchemaName
,x.TableName
,x.ColumnName
,ColumnExists = IIF(c.name IS NOT NULL,1,0)
,RowNum = ROW_NUMBER() OVER (PARTITION BY 1 ORDER BY x.TableName DESC)
--you can add data type by getting from sys.columns and sys.types if desired
FROM
cteColumnsTableCross x
LEFT JOIN sys.tables t
ON x.TableName = t.name
AND x.schema_id = t.schema_id
LEFT JOIN sys.columns c
ON t.object_id = c.object_id
AND x.ColumnName = c.name
)
, cteSelectStatements AS (
SELECT
TableName = t.name
,TableSelect = 'SELECT TableName = ''' + t.name + ''', ' +
STUFF(
(SELECT ', ' + c.ColumnName + ' = ' + IIF(c.ColumnExists = 0,'NULL',c.ColumnName)
FROM
cteColumns c
WHERE t.name = c.Tablename
FOR XML PATH(''))
,1,1,'')
+ ' FROM ' + t.name +
IIF((ROW_NUMBER() OVER (PARTITION BY 1 ORDER BY t.name DESC)) > 1,' UNION ALL ','')
FROM
sys.tables t
)
SELECT #SQLStatement = STUFF(
(SELECT ' ' + TableSelect
FROM
cteSelectStatements
ORDER BY
TableName
FOR XML PATH(''))
,1,1,'')
PRINT #SQLStatement
--EXECUTE #SQLStatement

SQL - Query only the first 25 columns in that table

75 columns in a table - I want to query only the first 25 columns in that table without naming each column name.... can you assist with a SQL query....
I been playing with the following:
Select Table_Name, Count(*) As ColumnCount
From Information_Schema.Columns
Group By Table_Name
Order By Table_Name
Doesn't meet my output........
If a Table has 75 columns, How can I see the first 25 columns without naming each column name? Don't want to delete Columns Only want to see the first 25 columns out of 75 columns in the same table.....TOP is not enable need another work around....
First 25 columns in a table query built into #query and then executed. Substitute correct #target_table value.
DECLARE
#target_table sysname
, #query nvarchar(max)
SET
#target_table = '_dimAreaOverlay'
; with of_interest as
(
SELECT
SS.name AS schemaname
, T.name AS tablename
, SC.name AS columname
FROM
sys.schemas SS
inner join
sys.tables T
ON T.schema_id = SS.schema_id
inner join
sys.columns SC
ON SC.object_id = T.object_id
WHERE
T.name = #target_table
AND SC.column_id < 26
)
, c AS
(
SELECT
STUFF((
SELECT
',' + QUOTENAME(I.columname)
FROM
of_interest I
FOR XML PATH('')), 1,1, '') AS column_list
, OI.tablename
, OI.schemaname
FROM
of_interest OI
GROUP BY
OI.schemaname
, OI.tablename
)
SELECT
#query = 'SELECT '
+ C.column_list
+ ' FROM '
+ QUOTENAME(C.schemaname)
+ '.'
+ QUOTENAME(C.tablename)
FROM C
EXECUTE(#query)
Find the table in Management Studio Object Explorer.
Right click it and choose Script Table As -> Select To -> New Query Editor Window
Delete unwanted columns.

Creating table from structure of another table with no data

How can this be achieved in SQL (MS SQL)
Thanks
OK: let me bit clear what am trying to acheive is generating dynamic select statement with EXCEPT clause.
eg: select col1,col2,col3 from #table
except
select col1,col2,col2 from #table
so my resultset will be always different based on #table
futher down i want to use this #table in CTE
with filteredData
as
(
select col1, col2 from temptable --(created above)
)
below is the code so far:
DECLARE #TABLENAME VARCHAR(200) = 'SERVICE_DELIVERY_LOCATION';
DECLARE #COLCOUNT INT ;
DECLARE #TEMPCOLNAME VARCHAR(500) ;
DECLARE #SELECTCOLUMNS VARCHAR(5000)='';
DECLARE #EXCEPTSTATEMENT VARCHAR(5000)='' ;
---------------------------------------------------------------------------------------------------
--CASE: GET COMMON_COLUMNS COLUMNS OF SOURCE AND DESTINATION TABLE
---------------------------------------------------------------------------------------------------
DECLARE #COMMON_COLUMNS TABLE( COLUMN_NAME VARCHAR(500))
INSERT INTO #COMMON_COLUMNS
SELECT SOURCE.COLUMN_NAME FROM SCD_SOURCE.INFORMATION_SCHEMA.COLUMNS SOURCE
INNER JOIN SCD_DESTI.INFORMATION_SCHEMA.COLUMNS DESTI ON SOURCE.COLUMN_NAME = DESTI.COLUMN_NAME
---------------------------------------------------------------------------------------------------
--CASE: GET PK COLUMNS OF SOURCE TO MAP TO DESTINATION IN CASE WHERE NEED TO DO UPDATES
---------------------------------------------------------------------------------------------------
DECLARE #PK_COLUMNS TABLE ( PK_COLUMN VARCHAR(500))
INSERT INTO #PK_COLUMNS
SELECT KCU.COLUMN_NAME
FROM SCD_SOURCE.INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS TC
JOIN SCD_SOURCE.INFORMATION_SCHEMA.KEY_COLUMN_USAGE AS KCU ON KCU.CONSTRAINT_SCHEMA = TC.CONSTRAINT_SCHEMA
AND KCU.CONSTRAINT_NAME = TC.CONSTRAINT_NAME
AND KCU.TABLE_SCHEMA = TC.TABLE_SCHEMA
AND KCU.TABLE_NAME = TC.TABLE_NAME
AND KCU.COLUMN_NAME != 'CREATE_DATA_CONTAINER_ID'
WHERE TC.CONSTRAINT_TYPE IN ('PRIMARY KEY')
SELECT #COLCOUNT = COUNT(*) FROM #COMMON_COLUMNS
WHILE ( #COLCOUNT != 0 )
BEGIN
SET #TEMPCOLNAME = (SELECT TOP 1 COLUMN_NAME FROM #COMMON_COLUMNS)
SET #SELECTCOLUMNS = #SELECTCOLUMNS + #TEMPCOLNAME + ', '
DELETE FROM #COMMON_COLUMNS WHERE COLUMN_NAME = #TEMPCOLNAME
SELECT #COLCOUNT = COUNT(*) FROM #COMMON_COLUMNS
END
SET #SELECTCOLUMNS = SUBSTRING(#SELECTCOLUMNS, 1, LEN(#SELECTCOLUMNS) - 1)
SET #EXCEPTSTATEMENT = 'SELECT ' + #SELECTCOLUMNS + ' FROM SCD_SOURCE.DBO.' + #TABLENAME + ' EXCEPT SELECT ' + #SELECTCOLUMNS + ' FROM SCD_DESTI.DBO.' + #TABLENAME
EXEC(#EXCEPTSTATEMENT)
want the resultset of last line into temptable
thanks
SELECT TOP 0 *
INTO NewTable
FROM OriginalTable
This will copy the structure, but won't copy constraints etc.
If you want everything, best thing to do is just generate the script from SSMS and change the table/constraint/index names.
Edit:
Re: "want the resultset of last line into temptable"
You could change the last 2 lines to:
SET #EXCEPTSTATEMENT = 'SELECT * INTO MyNewTable FROM (SELECT ' + #SELECTCOLUMNS + ' FROM SCD_SOURCE.DBO.' + #TABLENAME + ' EXCEPT SELECT ' + #SELECTCOLUMNS + ' FROM SCD_DESTI.DBO.' + #TABLENAME + ') x'
EXECUTE(#EXCEPTSTATEMENT)
This would put the resultset into a "real" table; alterneratively you'd have to use a global temporary table (just change "MyTable" to "##MyTable"). It wouldn't work with a local temporary table ("#MyTable") as the scope of that would be within the EXECUTE statement i.e. after the EXECUTE, you couldn't have code that then queried the local temporary table as it won't exist in that scope. Hence, it would need to be a real table, or a global temporary table (which would be accessible outside of the current scope)/
Open your managment studio, right click to your table and create to -> New Query window. This will generate the query for creating exact copy of your table with indexes constraints etc...
I've used this answer / script before.
SELECT *
INTO NewTable
FROM OriginalTable
WHERE 1 = 0