Global Update (All Rows) On One SQL Table With The Same Criteria - sql

IS there a way to run this across every column in a table:
UPDATE dbo.stage_a
SET Statement_Name= NULL
WHERE Statement_Name='""';
I am trying to tidy up after a data import.

Dynamic query plus Information_schema.columns. Try this.
DECLARE #cols NVARCHAR(max)='UPDATE dbo.stage_a set '
SELECT #cols += COLUMN_NAME + '=case when ' + COLUMN_NAME
+ ' = '""' then null else '+COLUMN_NAME+' end,'
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'stage_a'
AND TABLE_SCHEMA = 'dbo'
SELECT #cols = LEFT(#cols, Len(#cols) - 1)
PRINT #cols
EXEC Sp_executesql #cols

UPDATE Customers
SET ContactName='Alfred Schmidt', City='Hamburg'
WHERE CustomerName='Alfreds Futterkiste';
Like this example you should specify all coloumns.(separated by commas)
If you want to replace all coloumns with NULL why don't you delete the rows:
DELETE FROM Customers
WHERE CustomerName='Alfreds Futterkiste'

You meed to first get the all columns list by using the INFORMATION_SCHEMA.COLUMNS
DECLARE #tableName varchar(10)
SET #tableName = 'mm'
DECLARE #sql VARCHAR(MAX)
SET #sql = ''
SELECT #sql = #sql + 'UPDATE ' + #tableName + ' SET ' + c.name + ' = NULL WHERE ' + c.name + '= ''';'
FROM sys.columns c
INNER JOIN sys.tables t ON c.object_id = t.object_id
INNER JOIN sys.types y ON c.system_type_id = y.system_type_id
WHERE t.name = #tableName AND y.name IN ('varchar', 'nvarchar', 'char', 'nchar')
EXEC (#sql)
Query is not tested may need to tweak as per your need

Related

Dynamic SQL to get rows from information_schema

Let’s say I’m looking for a specific column in my database so I have something like this
SELECT COLUMN_NAME, TABLE_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE COLUMN_NAME like ‘%employeeid%’
But I also want to know how many rows each table has, I was told I can do this using Dynamic SQL so I have this now
DECLARE
#tableName NVARCHAR(MAX),
#sql NVARCHAR(MAX),
#colName NVARCHAR(MAX);
DECLARE CUR_TABLE CURSOR FOR
SELECT TABLE_NAME FROM INFORMATION_SCHEMA.COLUMNS
OPEN CUR_TABLE
FETCH NEXT FROM CUR_TABLE
INTO #tableName
WHILE ##FETCH_STATUS = 0
BEGIN
SET #colName = '%employeeid%'
SET #sql = 'SELECT COLUMN_NAME, TABLE_NAME, (SELECT COUNT(*) FROM ' + #tableName +') AS ROWS FROM INFORMATION_SCHEMA.COLUMNS where column_name like ' + ''' + #colName + ''';
FETCH NEXT FROM CUR_TABLE
INTO #tableName
END;
CLOSE CUR_TABLE
DEALLOCATE CUR_TABLE
EXEC sp_executesql #sql
But this doesn't work, What I'm trying to do is query a table with the column I am looking for, with the table name, and number of rows in the table.
How can I fix this?
You can make use of SQL Server's dynamic management views to quickly obtain the row counts*.
Find all tables with a column named 'MyColumn' and their current rows:
select Schema_Name(t.schema_id) schemaName, t.name TableName, s.row_count
from sys.columns c
join sys.tables t on t.object_id = c.object_id
join sys.dm_db_partition_stats s on s.object_id = c.object_id and s.index_id <= 1
where c.name='MyColumn';
* Accurate except for frequently updated tables where there could be some lag
The following uses INFORMATION_SCHEMA, dynamic SQL, and STRING_AGG() to build a query that will return a single result set.
DECLARE #ColumnName sysname = 'ProductID'
DECLARE #Newline VARCHAR(2) = CHAR(13) + CHAR(10)
DECLARE #SqlTemplate NVARCHAR(MAX) =
+ 'SELECT'
+ ' ColumnName = <ColumnNameString>,'
+ ' TableName = <TableSchemaAndNameString>,'
+ ' Rows = (SELECT COUNT(*) FROM <TableSchemaAndName>)'
+ #Newline
DECLARE #UnionSql NVARCHAR(100) = 'UNION ALL ' + #Newline
DECLARE #Sql NVARCHAR(MAX) = (
SELECT STRING_AGG(
REPLACE(REPLACE(REPLACE(
#SqlTemplate
, '<ColumnNameString>', QUOTENAME(C.COLUMN_NAME, ''''))
, '<TableSchemaAndNameString>', QUOTENAME(C.TABLE_SCHEMA + '.' + C.TABLE_NAME, ''''))
, '<TableSchemaAndName>', QUOTENAME(C.TABLE_SCHEMA) + '.' + QUOTENAME(C.TABLE_NAME))
, #UnionSql)
WITHIN GROUP(ORDER BY C.TABLE_SCHEMA, C.TABLE_NAME)
FROM INFORMATION_SCHEMA.TABLES T
JOIN INFORMATION_SCHEMA.COLUMNS C
ON C.TABLE_SCHEMA = T.TABLE_SCHEMA
AND C.TABLE_NAME = T.TABLE_NAME
WHERE T.TABLE_TYPE = 'BASE TABLE' -- Omit views
AND C.COLUMN_NAME = #ColumnName
)
SET #Sql = #Sql + 'ORDER BY Rows DESC, TableName' + #Newline
--PRINT #Sql
EXEC (#Sql)
I generalized it a bit by adding TABLE_SCHEMA so that it could be used with the AdventureWorks database. See this db<>fiddle for a working demo. Also included is equivalent logic that uses FOR XML instead of STRING_AGG for older SQL Server versions.
Assuming that you are using SQL Server, here is a shorthand way using sp_msforeachtable.
DECLARE #ColumnName NVARCHAR(200) = 'ContactID'
CREATE TABLE #T
(
ColumnName NVARCHAR(200),
TableName NVARCHAR(200),
RecordCount INT
)
INSERT INTO #T (ColumnName, TableName)
SELECT
ColumnName = C.COLUMN_NAME,
TableName = '['+C.TABLE_SCHEMA+'].['+C.TABLE_NAME+']'
FROM
INFORMATION_SCHEMA.COLUMNS C
WHERE
C.COLUMN_NAME LIKE '%' + #ColumnName + '%'
EXEC SP_MSFOREACHTABLE 'IF EXISTS(SELECT * FROM #T WHERE TableName = ''?'') UPDATE #T SET RecordCount = (SELECT COUNT(*) FROM ? ) WHERE TableName = ''?'''
SELECT
ColumnName,TableName,
TableType = CASE
WHEN RecordCount IS NULL
THEN 'View'
ELSE 'Table'
END,
RecordCount
FROM
#T
ORDER BY
CASE WHEN RecordCount IS NULL THEN 'View' ELSE 'Table' END
DROP TABLE #T

A query to get the MAX LEN of every field in a SQL table

I've been trying to come up with a query that will list the name of every column in a table with it's max length.
This is in SQL Server 2012.
Any help is greatly appreciated.
You can use below query to get the the Actual and used length of the columns in a table
DECLARE #TSQL VARCHAR(MAX) = ''
DECLARE #TableName sysname = 't1'
SELECT #TSQL = #TSQL + 'SELECT ' + QUOTENAME(sc.name, '''') + ' AS ColumnName, ' + QUOTENAME(t.name, '''') + ' AS DataType, ' +
QUOTENAME(sc.max_length, '''') + ' AS ActualLength, MAX(DATALENGTH(' + QUOTENAME(sc.name) + ')) AS UsedLength FROM '+#TableName+ char(10) +' UNION '
FROM sys.columns sc
JOIN sys.types t on t.system_type_id = sc.system_type_id and t.name != 'sysname'
WHERE sc.OBJECT_ID = OBJECT_ID(#TableName)
SET #TSQL = LEFT(#TSQL, LEN(#TSQL)-6)
EXEC(#TSQL)
If you want know your table detail use information_schema.columns
select *
from information_schema.columns
where table_name = 'YourTableName'
If you want the lenght of a string field use LEN
select len(field1)
from YourTableName

select columns with value NA

How to select columns in a table that only contain a specific value for all the rows? I am trying to find these columns to do an update on those values with a NULL value. In my columns I have varied range of values including NA
I am using SQL Server 2012.
I've tried doing: thsi only gives me column names. Can i add to this condition for columns with value 'NA'?
SELECT COLUMN_NAME AS NAMES,COLUMN_DEFAULT
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = 'dbo'
AND TABLE_NAME = 'ABC'
I am a beginner in SQL. Trying to figure out how to do this.
If min of column equals to max then that column contains same values:
Select
case when min(col1) = max(col1) then 1 else 0 end as Col1IsSame,
case when min(col2) = max(col2) then 1 else 0 end as Col2IsSame,
...
from Table
With dynamic query:
declare #s nvarchar(max) = 'select '
select #s = #s + 'case when min(' + COLUMN_NAME + ') = max(' +
COLUMN_NAME + ') then 1 else 0 end as ' + COLUMN_NAME + ','
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = 'dbo'
AND TABLE_NAME = 'Table'
Set #s = substring(#s, 1, len(#s) - 1) + ' from Table'
exec(#s)
TRY THIS QUERY
DECLARE #SQLQUERY NVARCHAR(MAX)
declare #tableName varchar(50)
DECLARE #NAME VARCHAR(50)
Declare #ParamDefinition AS NVarchar(2000)
Set #ParamDefinition = '#OIM VARCHAR(20)'
SELECT NAME
FROM sys.objects
WHERE [object_id]=#OIM
set #tableName= (SELECT NAME
FROM sys.objects
WHERE [object_id]=#OIM)
SET #NAME=(SELECT C.NAME
FROM sys.columns c
JOIN
sys.tables t ON c.object_id = t.object_id
WHERE c.name in (select distinct name
from sys.columns
where object_id=#OIM))
SET #SQLQUERY = ''
SELECT #SQLQUERY = #SQLQUERY + 'UPDATE ' + #tableName + ' SET ' + #NAME + ' = NULL WHERE ' + #NAME + ' = NA ; '
PRINT #SQLQUERY
Execute sp_Executesql #SQLQUERY , #ParamDefinition, #OIM
end

SQL Query for select from all column with same column name

I have multiple column with same name from multiple table,
table_1 has column X, table_2 has column x and more.
How to select query for X column from all table without union. If use union, i must write every table name on query statement, i don't do this. I want do like :
Select X from (All table with containing X) where X value (not X name) = 'ABC'.
I use Microsoft SQL.
Is it possible ? thanks
You can do that using dynamic SQL and build the query this way:
declare #sql as nvarchar(max) = N''
declare #columnname as nvarchar(100) = N'X'
declare #columnvalue as nvarchar(100) = N'ABC'
select #sql = #sql + N' UNION ALL SELECT ' + QUOTENAME(c.name) + N' FROM '
+ QUOTENAME(s.name) + N'.'
+ QUOTENAME(t.name)
+ N' WHERE ' + QUOTENAME(c.name) + N' = ''' + #columnvalue + ''''
from sys.columns c
inner join sys.tables t on c.object_id = t.object_id
inner join sys.schemas s on t.schema_id = s.schema_id
where c.name = #columnname
set #sql = STUFF(#sql, 1, 10, N'')
exec sp_executesql #sql
Try the following it will be useful to you.
Select a.x,b.x
from table_name a,table_name1 b
where a.x = b.x
and a.x = 'ABC';

Dynamic update statement with variable column names

We're looking to do an update in several SQL Server databases to change all NULL values in a certain table to be empty strings instead of NULL. We're potentially going to be doing this across hundreds of databases. The table name will always be the same, but the column names are variable based on how the front-end application is configured (don't judge... I didn't create this system).
Is there a way to do an update on all of these columns without knowing the column names ahead of time?
You can pass the name of the column in dynamic sql:
declare #sql nvarchar (1000);
set #sql = N'update table set ' + #column_name + '= ''''';
exec sp_executesql #sql;
You can look in the sys.columns table and join on the table name or object_id.
DECLARE #OBJ_ID INT
SELECT #OBJ_ID = OBJECT_ID
FROM SYS.tables
WHERE name = 'YOURTABLE'
SELECT * FROM SYS.columns
WHERE OBJECT_ID = #OBJ_ID
You could use the name field from the sys.columns query as a basis to perform the update on.
Assuming you want all columns of varchar/char types only (or change the type filter to whatever you need):
DECLARE #tableName varchar(10)
SET #tableName = 'yourtablenamehere'
DECLARE #sql VARCHAR(MAX)
SET #sql = ''
SELECT #sql = #sql + 'UPDATE ' + #tableName + ' SET ' + c.name + ' = '''' WHERE ' + c.name + ' IS NULL ;'
FROM sys.columns c
INNER JOIN sys.tables t ON c.object_id = t.object_id
INNER JOIN sys.types y ON c.system_type_id = y.system_type_id
WHERE t.name = #tableName AND y.name IN ('varchar', 'nvarchar', 'char', 'nchar')
EXEC (#sql)
This can be achieved with cursors. You first select the column names like #Darren mentioned, then you Set a Cursor with those values and loop:
Open oColumnsCursor
Fetch Next From oColumnscursor
Into #ColumnName
While ##FETCH_STATUS=0
Begin
Set #oQuery = 'Update [DB]..[Table] Set [' + #ColumnName + '] = ''NewValue'' Where [' + #ColumnName + '] = ''OldValue'''
Execute(#oQuery)
Fetch Next From oColumnscursor Into #ColumnName
Set #oCount = #oCount + 1
End
Close oColumnsCursor;
Deallocate oColumnsCursor;
This will work when you know the Table Name:
DECLARE #tableName varchar(10)
SET #tableName = 'Customers'
DECLARE #sql VARCHAR(MAX)
SET #sql = ''
SELECT #sql = #sql + 'UPDATE ' + #tableName + ' SET ' + c.name + ' = ISNULL('+ c.name +','''');'
FROM sys.columns c
INNER JOIN sys.tables t ON c.object_id = t.object_id
INNER JOIN sys.types y ON c.system_type_id = y.system_type_id
WHERE y.name IN ('varchar', 'nvarchar', 'char', 'nchar')
AND t.name = #tableName;
EXEC(#sql);
And this will iterate all Tables and all Columns in a Db:
DECLARE #sql VARCHAR(MAX)
SET #sql = ''
SELECT #sql = #sql + 'UPDATE ' + t.name + ' SET ' + c.name + ' = ISNULL('+ c.name +','''');'
FROM sys.columns c
INNER JOIN sys.tables t ON c.object_id = t.object_id
INNER JOIN sys.types y ON c.system_type_id = y.system_type_id
WHERE y.name IN ('varchar', 'nvarchar', 'char', 'nchar');
EXEC(#sql);
Below is the procedure.
ALTER PROCEDURE [dbo].[util_db_updateRow]
#colval_name NVARCHAR (30), -- column and values e.g. tax='5.50'
#idf_name NVARCHAR (300), -- column name
#idn_name NVARCHAR (300), -- column value
#tbl_name NVARCHAR (100) -- table name
AS
BEGIN
SET NOCOUNT ON;
DECLARE #sql NVARCHAR(MAX)
-- construct SQL
SET #sql = 'UPDATE ' + #tbl_name + ' SET ' + #colval_name +
' WHERE ' + #idf_name + '=' + #idn_name;
-- execute the SQL
EXEC sp_executesql #sql
SET NOCOUNT OFF
RETURN
END
Below is the stored procedure where you can pass Schema Name, Table Name and list of column names separted by comma.It works only in Sql Server 2016 or higher.
CREATE OR ALTER PROCEDURE UpdateData
(#SchemaName NVARCHAR(Max),#TableName NVARCHAR(MAX),#ColumnNames NVARCHAR(MAX))
AS
BEGIN
DECLARE #DynamicSql NVARCHAR(MAX);
SET #DynamicSql = 'UPDATE ' +'[' +#SchemaName+'].' + '[' +#TableName+']' +' SET ' + STUFF((SELECT ', [' + C.name + '] = ' + '''NEW_VALUE'''
FROM sys.columns C
INNER JOIN sys.tables T ON T.object_id = C.object_id
INNER JOIN sys.schemas S ON T.schema_id = S.schema_id
WHERE
T.name = #TableName
AND S.Name = #SchemaName
AND [C].[name] in (SELECT VALUE FROM string_split(#ColumnNames,','))
FOR XML PATH('')), 1,1, '')
print #DynamicSql;
EXEC (#DynamicSql);
END