SQL MERGE Table with tableName - sql

I would like have a generic procedure to Update my look Up Table.
CREATE TYPE S_Reference.[ReferenceType] as TABLE (
[Id] SMALLINT NOT NULL PRIMARY KEY,
[Code] VARCHAR(16) UNIQUE NOT NULL,
[Rank] SMALLINT NOT NULL CHECK([Rank]>0),
[Description] VARCHAR(128) NOT NULL,
[Base] BIT NOT NULL DEFAULT 0);
GO
CREATE PROCEDURE [S_Reference].[P_B_ReferenceMerge]
#Values [ReferenceType] READONLY,
#TableName NVARCHAR(50)
AS
DECLARE #SQLQuery NVARCHAR(200)
SET #SQLQuery = 'SELECT * FROM ' + #TableName
MERGE INTO #SQLQuery Ori
USING
#Values New
ON (Ori.[Id] = New.[Id])
WHEN MATCHED THEN
UPDATE
SET Ori.[Code] = New.[Code],
Ori.[Rank] = New.[Rank],
Ori.[Description] = New.[Description],
Ori.[Base] = New.[Base]
WHEN NOT MATCHED THEN
INSERT (Ori.[Id] , Ori.[Code], Ori.[Rank],Ori.[Description] ,Ori.[Base])
Values (New.[Id] , New.[Code], New.[Rank],New.[Description] ,New.[Base]);
RETURN 0
But I don't know how to use the "tableName" ?
I get an error on Ori.[Id], I think the problem comes from
SET #SQLQuery = 'SELECT * FROM ' + #TableName
MERGE INTO #SQLQuery Ori

If can help this is how I did. By this way You can manage easily the values in your look up (reference or enum in c#).
First the procedure:
CREATE TYPE S_Reference.[ReferenceType] AS TABLE (
[Id] SMALLINT NOT NULL PRIMARY KEY,
[Code] VARCHAR(40) UNIQUE NOT NULL,
[Rank] SMALLINT UNIQUE NOT NULL CHECK([Rank]>0),
[Description] VARCHAR(128) NOT NULL,
[Base] BIT NOT NULL DEFAULT 0);
GO
CREATE PROCEDURE [S_Reference].[P_M_ReferenceMerge]
#Values S_Reference.[ReferenceType] READONLY,
#TableName NVARCHAR(50)
AS
CREATE TABLE #NewValues (
[Id] SMALLINT NOT NULL PRIMARY KEY,
[Code] VARCHAR(40) UNIQUE NOT NULL,
[Rank] SMALLINT UNIQUE NOT NULL CHECK([Rank]>0),
[Description] VARCHAR(128) NOT NULL,
[Base] BIT NOT NULL DEFAULT 0);
Insert INTO #NewValues
select * From #Values
DECLARE #SQLQuery NVARCHAR(MAX)
SET #SQLQuery =
'DELETE
FROM ' + #TableName + '
WHERE [Id] IN (SELECT [Id]
FROM ' + #TableName + '
EXCEPT
SELECT [Id]
FROM #NewValues)
MERGE INTO ' + #TableName + ' Ori
USING #NewValues New
ON (Ori.[Id] = New.[Id])
WHEN MATCHED THEN
UPDATE
SET Ori.[Code] = New.[Code],
Ori.[Rank] = New.[Rank],
Ori.[Description] = New.[Description],
Ori.[Base] = New.[Base]
WHEN NOT MATCHED THEN
INSERT ([Id] , [Code], [Rank], [Description] ,[Base])
Values (New.[Id] , New.[Code], New.[Rank], New.[Description] ,New.[Base]);'
EXEC sp_executesql #SQLQuery
RETURN 0
Usage
INSERT INTO
#VALUES([Id],[Code],[Rank],[Description] ,[Base])
Values
(1,'EUR',1,'EUR',0),
(2,'GBP',2,'GBP',0),
(3,'USD',3,'USD',0)
EXEC [S_Reference].[P_M_ReferenceMerge]
#Values = #VALUES,
#TableName = 'S_Reference.T_R_Currency'
DELETE FROM #VALUES

Related

Create multiple tables through a "while" or procedure

I'm trying to create a procedure to create multiple tables at once, either using a while or another command.
This is the database I have to create, but I was wondering if there was a faster way to do it through a loop:
The creation of column fields or fields in tables are the same. The problem arises when naming the tables created, since there are several.
declare #i int = 1
while (#i <= 11)
begin
declare #nameoftable nvarchar(50)
set #nameoftable ='dbo'+ '.' + 'tbl_' + convert(nvarchar, #i) + '000_Capitulo_100'
print #nameoftable
create table #nameoftable
(
cap100ID int primary key not null,
ccdd int not null,
ccpp int not null,
ccdi int not null,
tipoVia nvarchar(20) not null,
nombVia nvarchar(50) not null
)
set #i = #i + 1
end;
This is the code that I advanced so far in sql server management.
Got to agree with the comments regarding having multiple tables with identical structure and the possible problems it could cause but if you really need to do this you could use EXEC.
declare #i int = 1
while (#i <= 11)
begin
declare #nameoftable nvarchar(50)
declare #sqlCommand nvarchar(255)
set #nameoftable ='dbo'+ '.' + 'tbl_' + convert(nvarchar, #i) + '000_Capitulo_100'
SET #sqlCommand = 'create table ' + #nameoftable +
'(cap100ID int primary key not null,
ccdd int not null,
ccpp int not null,
ccdi int not null,
tipoVia nvarchar(20) not null,
nombVia nvarchar(50) not null)'
EXEC (#sqlCommand)
set #i = #i + 1
end;
not sure , this is what your are looking for?
EXEC('create table '+#nameoftable+'
(
cap100ID int primary key not null,
ccdd int not null,
ccpp int not null,
ccdi int not null,
tipoVia nvarchar(20) not null,
nombVia nvarchar(50) not null
)')

Add columns from one to another table dynamically in SQL Server

I have 2 tables, A and B. Table A has columns Q1, Q2, Q3, Q4 and Table B has columns Q1 and Q2 along with others. In Table A, columns will get changed in future with Q5, Q6, Q7 etc. I want to write dynamic SQL to alter the table B (adding new columns) whenever new columns are added to Table A. Columns which will get added always be like Q1, Q2,Q3...Q40.
example of my tables:
create table tableA
(
[sid] [varchar](50) not null,
[rid] [varchar](50) not null,
[Q_URL] [varchar](500) null,
[Q1] int null,
[Q2] int null,
[Q3] int null,
[Q4] int null
);
create table tableB
(
[s_id] [varchar](50) not null,
[rid] [varchar](50) not null,
[Q_URL] [varchar](500) null,
[Q1] int null,
[Q2] int null
);
if object_id('tempdb..#source_col') is not null
drop table #source_col
Select distinct column_name as source_r_column from hr.INFORMATION_SCHEMA.COLUMNS
where table_name = 'tableA'
and column_name like 'Q%'
and column_name <> 'Q_URL';
if object_id('tempdb..#destination_col') is not null
drop table #source_col
Select distinct column_name as source_r_column from hr.INFORMATION_SCHEMA.COLUMNS
where table_name = 'tableB'
and column_name like 'Q%'
and column_name <> 'Q_URL';
if object_id('tempdb..#newcols') is not null
drop table #newcols
Select row_number() over(order by t1.source_q_columns) as colnum,t1.source_q_columns, 'int' as datatype
into #newcols
from #tableA t1
left join #tableB t2 on t1.source_q_columns= t2.destination_q_columns
where t2.destination_q_columns is null;
Declare #sql nvarchar(max)
Declare #column varchar(10)
Declare #datatype varchar(10)
Declare #max_colnum int
set #max_colnum = (select max(colnum) from #newcols)
While(#max_colnum != 0)
begin
set #column = (select source_q_columns from #newcols where colnum = #max_colnum)
print #column
select #sql = 'Alter Table destination Add '+ #column + ' int null'
print #sql
EXEC (#sql)
set #max_colnum = #max_colnum -1
end
This is what i came up. I believe this will work for any case. :)
You can create something called a DDL Trigger for Alter Table event. The Trigger is created on the database level so it will fire for any Alter table commands executed on the database.
A sample of DDL trigger for Alter table event on the database level for TableA would look something like this.
CREATE TRIGGER tr_Replicate_DDL_For_TableA
ON DATABASE
FOR ALTER_TABLE
AS
BEGIN
SET NOCOUNT ON;
Declare #data xml = EVENTDATA()
,#TableName SYSNAME
,#Sql NVARCHAR(MAX);
SET #TableName = #data.value('(/EVENT_INSTANCE/ObjectName)[1]', 'SYSNAME');
SET #Sql = #data.value('(/EVENT_INSTANCE/TSQLCommand)[1]', 'nvarchar(max)');
IF (#TableName = 'TableA') --<-- only replicate changes if TableA's schema changed.
BEGIN
SET #sql = REPLACE(#sql , 'TableA' , 'TableB');
Exec sp_executesql #sql;
END
END
GO

SQL Server insert into with dynamic parameters

I'm trying to make a dynamic stored procedure for inserting records in tables where I pass in table name, schema name and insert values parameters.
I've made it to select column names from table parameter and store it in a variable, but I can't manage how to make insert statement work.
Please if anyone can help me.
Here is my query:
DECLARE #TableName VARCHAR(100)
DECLARE #SchemaName VARCHAR(10)
DECLARE #Columns NVARCHAR(max)
DECLARE #VALUES NVARCHAR(MAX)
SET #SchemaName = 'dbo'
SET #TableName = 'CLASSROOMS'
SET #Columns = '';
SET #VALUES = 'Classroom1,25'
SELECT #Columns = #Columns + CAST(COLUMN_NAME AS varchar(50)) + ','
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = #TableName
AND TABLE_SCHEMA = #SchemaName
AND ORDINAL_POSITION > 1
SET #Columns = SUBSTRING(#Columns, 1, Len(#Columns) - 1)
--SELECT #Columns
DECLARE #SQL AS NVARCHAR(MAX)
SET #SQL=N'INSERT INTO ' + #TableName + '(' + #Columns + ') VALUES (' + #VALUES + ')'
EXEC sp_executesql #SQL
And here is Classroom table create script:
CREATE TABLE [dbo].[CLASSROOMS]
(
[ClassRoomID] [INT] IDENTITY(1,1) NOT NULL,
[ClassRoomName] [NVARCHAR](50) NOT NULL,
[MaxSits] [INT] NOT NULL,
CONSTRAINT [PK_CLASSROOMS]
PRIMARY KEY CLUSTERED ([ClassRoomID] ASC)
) ON [PRIMARY]
Thank you in advance
Try this:
SET #VALUES='''Classroom1'',25'
The [ClassRoomName] is a nvarchar field.

SQL INDENTITY DOESN'T RECEIVE PARAMETERS

I'm trying to set IDENTITY seed parameter while creating table, getting it from a var. Something like this
DECLARE #MaxID INTEGER
SET #MaxID = (SELECT TOP 1 ID FROM dbo.ProductQuotes ORDER BY ID DESC) + 1;
CREATE TABLE [dbo].[Z](
[ID] int PRIMARY KEY not null IDENTITY(#MaxID,1),
[Number] int NULL,
[Name] nvarchar(50) COLLATE Cyrillic_General_CI_AS NULL
) ON [PRIMARY]
GO
Error is "incorrect syntax near '#MaxID' (in this row [ID] int PRIMARY KEY not null IDENTITY(#MaxID,1) )
But I'm not sure it's about syntax at all. Can somebody explain me where am I wrong here? :)
This cannot be parameterised.
You would need to use dynamic SQL as below.
DECLARE #MaxID INTEGER
SELECT #MaxID = 1 + ISNULL(MAX(ID),0) FROM dbo.ProductQuotes
DECLARE #Script NVARCHAR(MAX) =
N'
CREATE TABLE [dbo].[Z](
[ID] int PRIMARY KEY not null IDENTITY(' + CAST(#MaxID AS NVARCHAR(10)) + ',1),
[Number] int NULL,
[Name] nvarchar(50) COLLATE Cyrillic_General_CI_AS NULL
) ON [PRIMARY]
'
EXEC (#Script);
I assume you will take precautions to ensure that ProductQuotes cannot be subject to any inserts during the import process.
Something like
DECLARE #MaxID INTEGER
DECLARE #SQL varChar(4000)
SET #MaxID = (SELECT TOP 1 ID FROM dbo.ProductQuotes ORDER BY ID DESC) + 1;
Set #SQL = 'CREATE TABLE [dbo].[Z]([ID] int PRIMARY KEY not null IDENTITY(' +
Convert(VarChar(8),#MaxID) +
',1), [Number] int NULL, [Name] nvarchar(50) COLLATE Cyrillic_General_CI_AS NULL) ON [PRIMARY]
Exec(#sql)
Build the sql statement using the teh value of #MaxID then execute it.

Selecting not null column

I have a table with varbinary(max) column and nvarchar(max) column. One of them is null and the other has a value.
I would like to return the column that has the value as a varbinary(max) column. So far I have tried this, that does not work:
SELECT
A =
CASE A
WHEN NULL THEN B
ELSE A
END
FROM Table
SELECT COALESCE(A, CAST(B As varbinary(max)))
UPDATE: In response to comments (thanks) and assuming B is the nvarchar(max) column, I have moved the CAST inside the COALESCE
Try SELECT ISNULL(A, cast(B AS varbinary(max))) FROM TABLE
Your case statement evaluates to the dreaded A = NULL:
CASE A WHEN NULL THEN B ELSE A END
Is the same as:
CASE WHEN A = NULL then B ELSE A END
One way to fix this is to use A IS NULL, like:
CASE WHEN A IS NULL THEN B ELSE A END
Or even simpler:
COALESCE(A,B)
Both the when and the coalesce will assume the data type of the first argument. To cast the result to varbinary, you can place the varbinary column first, or explicitly cast:
COALESCE(CAST(A AS VARBINARY(MAX)),B)
here is the full code of create table and insert value and apply my code and only retrieve not null value
CREATE TABLE [dbo].[SUPPLIER](
[ID] [int] IDENTITY(1,1) NOT NULL,
[SUPPLIER_NAME] [varchar](100) NOT NULL,
[ADDRESS] [varchar](150) NULL,
[CREATE_DATE] [datetime] NULL,)
INSERT INTO [MyPayrol].[dbo].[SUPPLIER]
([SUPPLIER_NAME]
,[CREATE_DATE])
VALUES
('Khaled Nabil'
,GETDATE())
declare #inumberofcolumn int
select #inumberofcolumn= count(*)
from sys.columns where OBJECT_NAME(object_id) = 'supplier'
declare #nameofcolumn varchar(100)
set #nameofcolumn =''
declare #counter int
set #counter=1
declare #colname varchar(100)
declare #statment varchar(100)
declare #value varchar(100)
while #counter <=#inumberofcolumn
begin
select #colname= COL_NAME(object_id('[dbo].[SUPPLIER]'),#counter)
declare #data table ([value] varchar(100))
--set #statment = 'select '+#colname+' from [dbo].[SUPPLIER]'
insert #data exec ('SELECT top 1 '+ #colname +' from [dbo].[SUPPLIER]')
select #value = [value] from #data
if #value is not null
begin
if #counter = 1
begin
set #nameofcolumn = #nameofcolumn + #colname
end
else
begin
set #nameofcolumn = #nameofcolumn + ','+ #colname
end
end
set #counter = #counter+1
end
execute ('select '+#nameofcolumn+' from [dbo].[SUPPLIER]')