How do I select a column name into a variable rather than the content of the column? - sql-server-2016

I am looping through a bunch of columns (all beginning with RUA6) and for the one (there will always be exactly one) that has the value 'R' I want to set the name of this column as another variable. I'm doing the following but I don't know how to grab the name of the column and not the value.
DECLARE #RUA6isRef varchar(255)
DECLARE #RUA6vars varchar(255)
DECLARE crsTo CURSOR
FOR
SELECT COLUMN_NAME
FROM INFORMATION_SCHEMA.Columns
WHERE TABLE_NAME = 'VenUS6_M0Inv'
AND COLUMN_NAME LIKE 'RUA6%'
OPEN crsTo
FETCH NEXT FROM crsTo
INTO #RUA6vars
WHILE ##FETCH_STATUS = 0
BEGIN
IF #RUA6vars = 'R' SELECT #RUA6isRef = #RUA6vars
FETCH NEXT FROM crsTo
INTO #RUA6vars
END
CLOSE crsTo
DEALLOCATE crsTo

Related

T-SQL script to update numerous prod tables from temp tables

I am trying to simplify the updating of numerous production tables from temp tables. I currently have a long script that uses the MERGE command, but as I increase the number of tables to be processed, the MERGE code is getting unwieldy. To simplify, my idea is to create a script that will get the table names into a cursor, get the field names for that table into a different cursor, then compare temp and prod values. If different, I will update the prod table.
The table 'TableManifest' has only 1 column called TableName.
So 2 questions
1 - Is this an efficient approach to the problem? I'd love to get other suggestions.
2 - This code fails with an error "Must declare the table variable #Temp_TableName" on the line that starts with 'IF(SELECT..'.
DECLARE #TableName varchar(MAX) -- TARGET Table to update
DECLARE #Temp_TableName varchar(MAX) -- SOURCE Table for compare
DECLARE #ColumnNames varchar(MAX) -- Table Column to compare
-- Create CURSOR of Tables to process
DECLARE C_TableNames CURSOR FOR SELECT TableName FROM TableManifest
OPEN C_TableNames
-- Get 1st table name
FETCH NEXT FROM C_TableNames INTO #TableName
WHILE ##FETCH_STATUS = 0
BEGIN
-- Create variable for TEMP table name
SELECT #Temp_TableName = CONCAT('TEMP_',#TableName)
-- Create CURSOR of Column Names in the table
DECLARE C_ColumnNames CURSOR FOR SELECT name FROM sys.columns WHERE object_id = OBJECT_ID(#TableName)
OPEN C_ColumNames
-- Get 1st column name
FETCH NEXT FROM C_ColumnNames INTO #ColumnNames
WHILE ##FETCH_STATUS = 0
BEGIN
-- If the column name is not 'ID' and the values are different, update the TARGET table
IF(SELECT #ColumnNames FROM #Temp_TableName) <> (SELECT #ColumnNames FROM #TableName) AND #ColumnNames <> 'id'
UPDATE #TableName SET #ColumnNames = (SELECT #ColumnNames from #Temp_TableName)
-- Get next column name
FETCH NEXT FROM C_ColumnNames INTO #ColumnNames
END
-- Get next table name
FETCH NEXT FROM C_TableNames INTO #TableName
END
-- Clean up
CLOSE C_ColumNames
DEALLOCATE C_ColumNames
CLOSE C_TableNames
DEALLOCATE C_TableNames

How to compare each string from first column with each string in second column in TSQL?

Here is the code I tried:
declare #o1 nvarchar(255)
declare #o2 nvarchar(255)
declare data cursor for
select o1.Name, o2.Name from MyDB.dbo.Table1 as o1, MyDB.dbo.MyTable2 as o2;
OPEN data;
-- Perform the first fetch.
FETCH NEXT FROM data into #o1, #o2;
-- Check ##FETCH_STATUS to see if there are any more rows to fetch.
WHILE ##FETCH_STATUS = 0
BEGIN
-- This is executed as long as the previous fetch succeeds.
FETCH NEXT FROM data INTO #o1, #o2;
Print 'Name1: ' + #o1
WHILE ##FETCH_STATUS = 0
BEGIN
-- This is executed as long as the previous fetch succeeds.
FETCH NEXT FROM data INTO #o1, #o2;
Print 'Name2: ' + #o2
END
END
CLOSE data;
DEALLOCATE data;
GO
I am getting two columns in my query and both are nvarchar(255).
I want to compare each value from the first column with each value of the second column. That can be achieved with loop inside a loop, but I don't know what should I do with the cursor part.
Should I put a variable and keep fetch status separately?
Or somethings else will do the trick?
I think that you don't need a cursor you can use select :
Select o1, O2
from table1
where o1 in (select o2 from table1)

Ho to update a field in tableA if it contains certain string that is present in another field(in reference table)?

I am trying to standardise col_value(field) if it contains the string that is present in reference table. The valid_value will be replaced with invalid and the whole string will be updated to updated_col_value in TableA.
Table structures:
Basetabe: TableA
col_value,updated_col_value
ReferenceTable
Invalid_value, Valid_value
Currently to achieve this, i have written a cursor where i am passing every record and execute update statement. Which is why number of records= number of update statement. It makes my proc really really slow.
I just wanna make it in a single update statement instead of executing updating statement for each time. Could you please help.
Below is my current proc
SET #SQL_STR = 'SELECT col_value FROM TABLEA'
SET #VSQL = 'SET #CURSOR = CURSOR FORWARD_ONLY STATIC FOR ' + #SQL_STR + ' OPEN #CURSOR;'
EXEC SYS.SP_EXECUTESQL
#VSQL
,N'#CURSOR CURSOR OUTPUT'
,#update_column_cusror OUTPUT
fetch next from #update_column_cusror into #Col_value_variable
WHILE ##FETCH_STATUS = 0
BEGIN
set #updated_col_value_v=''
DECLARE get_valid_value_cursor CURSOR FOR
SELECT Invalid_value FROM REFERENCETABLE
open get_valid_value_cursor
fetch next from get_valid_value_cursor into #invalid_value_variable
WHILE ##FETCH_STATUS = 0
Begin
select #Char_to_replace = Valid_Value from REFERENCETABLE where Invalid_value=#invalid_value_variable
if #updated_col_value_v=''
set #replaced_value = replace(#Col_value_variable,#invalid_value_variable,#Char_to_replace)
else
set #replaced_value = replace(#updated_col_value_v,#invalid_value_variable,#Char_to_replace)
set #updated_col_value_v = #replaced_value
SET #SQL= '
update TABLEA
set updated_col_value='''+#updated_col_value_v+'''
where col_value='''+#Col_value_variable+'''
EXECUTE(#SQL)
fetch next from get_valid_value_cursor into #invalid_value_variable
End
close get_valid_value_cursor
deallocate get_valid_value_cursor
Could you please check following SQL Server Trigger on main table which validates entries and corrects from reference table
I hope it helps
create trigger ValidateEntries on TableA after Insert, Update
as
begin
update TableA
set
col_value = r.Valid_value,
updated_col_value = i.col_value
from inserted as i
inner join ReferenceTable r
on i.col_value = r.Invalid_value
where TableA.col_value = i.col_value
end
go

SQL Server - Select columns that meet certain conditions?

My COLUMNS can contain only three values or var chars - economy, basic, luxury. I want to select a ROW and display only those COLUMNS which contain luxury. The problem is that there are many such columns - about 50. I don't want to type the names of all those columns in my select query. Is there a shorter and simpler alternative to this ? Which query should I use ?
I am thinking of something like this (this is a FAKE query) -
#declare Column_Name varchar(30)
select Column_Name where Column_Value = 'luxury'
from ATable
where rowId = 'row 5';
Table structure -
rowId | Column1 | Column2 | Column3.....
I've created a stored procedure for you.
This procedure examines the MSSQL meta to build a dynamic SQL string that returns a result containing column names N and their values V, and the corresponding row key K from which that value was retrieved, for a specified table.
When this is executed, the results stored in a global temporary table called ##ColumnsByValue, which can then be queried directly.
Create the GetColumnsByValue stored procedure, by executing this script:
-- =============================================
-- Author: Ben Roberts (sepster#internode.on.net)
-- Create date: 22 Mar 2013
-- Description: Returns the names of columns that contain the specified value, for a given row
-- =============================================
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF OBJECT_ID ( 'dbo.GetColumnsByValue', 'P' ) IS NOT NULL
DROP PROCEDURE dbo.GetColumnsByValue;
GO
CREATE PROCEDURE dbo.GetColumnsByValue
-- Add the parameters for the stored procedure here
#idColumn sysname,
#valueToFind nvarchar(255),
#dbName sysname,
#tableName sysname,
#schemaName sysname,
#debugMode int = 0
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from interfering with SELECT statements.
SET NOCOUNT ON;
DECLARE #SQL nvarchar(max);
DECLARE #SQLUnion nvarchar(max);
DECLARE #colName sysname;
DECLARE #dbContext nvarchar(256);
DECLARE #Union nvarchar(10);
SELECT #dbContext = #dbName + '.' + #schemaName + '.sp_executeSQL';
SELECT #SQLUnion = '';
SELECT #Union = '';
IF OBJECT_ID ( 'tempdb..##GetColumnsByValueIgnoreList') IS NULL -- no columns to ingore have been specified, need to create an empty list.
BEGIN
CREATE TABLE ##GetColumnsByValueIgnoreList (column_name nvarchar(255));
END
DECLARE DBcursor CURSOR FOR
SELECT
COLUMN_NAME
FROM
INFORMATION_SCHEMA.COLUMNS
WHERE
TABLE_NAME = #tableName
AND
TABLE_SCHEMA = #schemaName;
OPEN DBcursor;
FETCH DBcursor INTO #colName;
WHILE (##FETCH_STATUS = 0)
BEGIN
IF (
#colName != #idColumn
AND
#colName NOT IN (SELECT column_name FROM ##GetColumnsByValueIgnoreList)
)
BEGIN
SELECT #SQL = 'SELECT '+#idColumn+' as K, '''+#colName+''' as N, ' +#colName+ ' as V FROM ' + #dbName + '.' + #schemaName + '.' + #tableName;
--PRINT #SQL;
SELECT #SQLUnion = #SQL + #Union + #SQLUnion;
SELECT #Union = ' UNION ';
END
FETCH DBcursor INTO #colName;
END; -- while
CLOSE DBcursor; DEALLOCATE DBcursor;
IF (#debugMode != 0)
BEGIN
PRINT #SQLUnion;
PRINT #dbContext;
END
ELSE
BEGIN
-- Delete the temp table if it has already been created.
IF OBJECT_ID ('tempdb..##ColumnsByValue') IS NOT NULL
BEGIN
DROP TABLE ##ColumnsByValue
END
-- Create a new temp table
CREATE TABLE ##ColumnsByValue (
K nvarchar(255), -- Key
N nvarchar(255), -- Column Name
V nvarchar(255) -- Column Value
)
-- Populate it with the results from our dynamically generated SQL.
INSERT INTO ##ColumnsByValue EXEC #dbContext #SQLUnion;
END
END
GO
The SP takes several inputs as parameters, these are explained in the following code.
Note also I've provided a mechanism to add an "ignore list" as an input:
This allows you to list any column names that should not be included
in the results.
You do NOT need to add the columnn that you're using as your key, ie the row_id from your example structure.
You MUST include other columns that are not varchar as
these will cause an error (as the SP just does a varchar comparison
on all columns it looks at).
This is done via a temp table that you must create/populate
Your example table structure suggests
the table contains only columns of interest, so this may not apply to
you.
I've included example code for how to do this (but only do this if you need to):
IF OBJECT_ID ( 'tempdb..##GetColumnsByValueIgnoreList') IS NOT NULL
BEGIN
DROP TABLE ##GetColumnsByValueIgnoreList;
END
CREATE TABLE ##GetColumnsByValueIgnoreList (column_name nvarchar(255));
INSERT INTO ##GetColumnsByValueIgnoreList VALUES ('a_column');
INSERT INTO ##GetColumnsByValueIgnoreList VALUES ('another_column');
INSERT INTO ##GetColumnsByValueIgnoreList VALUES ('yet_another_column');
Now, to fire off the procedure that build your temp table of results, use the following code (and modify as appropriate, of course).
-- Build the ##ColumnsByValue table
EXEC dbo.GetColumnsByValue
#idColumn = 'row_id', -- The name of the column that contains your row ID (eg probably your PK column)
#dbName = 'your_db_name',
#tableName = 'your_table_name',
#schemaName = 'dbo',
#debugMode = 0 -- Set this to 1 if you just want a print out of the SQL used to build the temp table, to 0 if you want the temp table populated
This leaves you with ##ColumnsByValue, on which you can perform whatever search you need, eg:
select * from ##ColumnsByValue WHERE v = 'luxury' and k = 5 --some_row_id
You'd need to re-execute the stored procedure (and if relevant, create/modify the ignore list table prior to it) for each table you want to examine.
A concern with this approach is the nvarchar length might get exceeded in your case. You'd prob. need to use different datatype, reduce the column name lengths etc. Or break it up into sub-steps and union the results together to get the resultset you're after.
Another concern I have is that this is complete overkill for your particular scenario, where a one-off script-to-query-window will give you the basis of what you need, then some clever text editing in eg Notepad++ will get you all the way there... and hence this problem will likely (and quite reasonably) put you off doing it this way! But it is a good general-case question, and so deserves an answer for anyone interested in future ;-)

process each row in table in stored procedure using cursor

My Scenario is bit different. what i am doing in my stored procedure is
Create Temp Table and insert rows it in using "Cursor"
Create Table #_tempRawFeed
(
Code Int Identity,
RawFeed VarChar(Max)
)
Insert Data in temp table using cursor
Set #GetATM = Cursor Local Forward_Only Static For
Select DeviceCode,ReceivedOn
From RawStatusFeed
Where C1BL=1 AND Processed=0
Order By ReceivedOn Desc
Open #GetATM
Fetch Next
From #GetATM Into #ATM_ID,#Received_On
While ##FETCH_STATUS = 0
Begin
Set #Raw_Feed=#ATM_ID+' '+Convert(VarChar,#Received_On,121)+' '+'002333'+' '+#ATM_ID+' : Bills - Cassette Type 1 - LOW '
Insert Into #_tempRawFeed(RawFeed) Values(#Raw_Feed)
Fetch Next
From #GetATM Into #ATM_ID,#Received_On
End
Now have to process each row in Temp Table using another Cursor
DECLARE #RawFeed VarChar(Max)
DECLARE Push_Data CURSOR FORWARD_ONLY LOCAL STATIC
FOR SELECT RawFeed
FROM #_tempRawFeed
OPEN Push_Data
FETCH NEXT FROM Push_Data INTO #RawFeed
WHILE ##FETCH_STATUS = 0
BEGIN
/*
What Should i write here to retrieve each row one at a time ??
One Row should get stored in Variable..in next iteration previous value should get deleted.
*/
FETCH NEXT FROM Push_Data INTO #RawFeed
END
CLOSE Push_Data
DEALLOCATE Push_Data
Drop Table #_tempRawFeed
What Should i write In BEGIN to retrieve each row one at a time ??
One Row should get stored in Variable..in next iteration previous value should get deleted.
Regarding your last question, if what you are really intending to do within your last cursor is to concatenate RawFeed column values into one variable, you don't need cursors at all. You can use the following (adapted from your SQL Fiddle code):
CREATE TABLE #_tempRawFeed
(
Code Int IDENTITY
RawFeed VarChar(MAX)
)
INSERT INTO #_tempRawFeed(RawFeed) VALUES('SAGAR')
INSERT INTO #_tempRawFeed(RawFeed) VALUES('Nikhil')
INSERT INTO #_tempRawFeed(RawFeed) VALUES('Deepali')
DECLARE #RawFeed VarChar(MAX)
SELECT #RawFeed = COALESCE(#RawFeed + ', ', '') + ISNULL(RawFeed, '')
FROM #_tempRawFeed
SELECT #RawFeed
DROP TABLE #_tempRawFeed
More on concatenating different row values into a single string here: Concatenate many rows into a single text string?
I am pretty sure that you can avoid using the first cursor as well. Please, avoid using cursors, since the really hurt performance. The same result can be achieved using set based operations.