SQL INDENTITY DOESN'T RECEIVE PARAMETERS - sql

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.

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 MERGE Table with tableName

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

Does this query require dynamic sql? SQL Server

I want to select the parameters of a stored procedure and then check whether each parameter is null or not in a loop.
The problem I'm having is that when I want to evaluate the variable in the IF statement, it is not being evaluated correctly. I want to evaluate each parameter I stored in the table variable. I don't know the syntax for this...or maybe it isn't even possible?
Does this require Dynamic SQL? If so, when executing dynamic sql, the value of the variable will be out of scope so how do I deal with that?
I verified everything up to the IF statement works.
CREATE PROCEDURE dbo.UpdateBank
(
#BankKey [smallint] = NULL,
#Bank [varchar] (30) = NULL,
#BankCode [char] (4) = NULL,
#MasterBankCode [char] = NULL,
#Bin [char] (6) = NULL,
#WebSite [varchar] (50) = NULL,
#isActive [bit] = NULL,
#CreateDate [smalldatetime] = NULL
)
AS
SET NOCOUNT ON
SET ANSI_NULLS OFF
DECLARE #MaxRow TINYINT, #Count TINYINT
DECLARE #SPName VARCHAR (128), #CurrentRow TINYINT
SET #SPName = OBJECT_NAME(##PROCID) -- SP self-reference to find its current name
DECLARE #SPParametersList TABLE (ID INT Identity(1,1) Primary Key,
ParameterName NVARCHAR (128),
DataType NVARCHAR (128),
ParameterMode NVARCHAR (10))
CREATE TABLE #TempExec(ID INT Identity(1,1) Primary Key,
Num BIT)
INSERT INTO #SPParametersList (ParameterName, Datatype, ParameterMode)
SELECT PARAMETER_NAME,DATA_TYPE,PARAMETER_MODE
FROM INFORMATION_SCHEMA.PARAMETERS
WHERE SPECIFIC_NAME = #SPName
SET #CurrentRow = 1
SELECT #MaxRow = ISNULL(MAX(ID),0) FROM #SPParametersList
WHILE #CurrentRow <= #MaxRow
BEGIN
IF ((SELECT ParameterName FROM #SPParametersList WHERE ID = #CurrentRow) <> NULL)
BEGIN
SELECT 'Success'
SET #Count = #Count + 1
END
SELECT 'Fail'
SET #CurrentRow = #CurrentRow + 1
END
SELECT #Count
I always get 'Fail' when I run this stored proc
Change your line:
IF ((SELECT ParameterName FROM #SPParametersList WHERE ID = #CurrentRow) <> NULL)
to
IF ((SELECT ParameterName FROM #SPParametersList WHERE ID = #CurrentRow) IS NOT NULL)
You also need to initialize the #Count variable to 0:
SET #Count = 0
SET #CurrentRow = 1
SELECT #MaxRow = ISNULL(MAX(ID),0) FROM #SPParametersList
Probably the issue is in the <> NULL which should
IF EXISTS(SELECT ParameterName FROM #SPParametersList WHERE ID = #CurrentRow)
but I'm not sure what you want to achieve with that piece of code...
I suspect that this is an example of a query that can be rewritten without the use of loops/cursors (most sql is in my experience...)
Does the query below give you your desired results?
with temp as
(
SELECT '#BankKey' as ParamName
UNION
SELECT '#Bank'
)
SELECT COUNT(*) as myCount
FROM INFORMATION_SCHEMA.PARAMETERS as isp
LEFT JOIN temp as t
ON t.ParamName = isp.PARAMETER_NAME
WHERE SPECIFIC_NAME = #SPName AND t.ParamName is null
You should try to avoid using Loops/Cursors as much as possible. SQL Server (and most DBMSs in general) are excellent at performing Set based operations and terrible at performing row based operations (loops/cursors).
(1) "I always get 'Fail' when I run this stored proc": you have forget the ELSE branch
IF ((SELECT ParameterName FROM #SPParametersList WHERE ID = #CurrentRow) /*<>*/ IS NOT NULL)
BEGIN
SELECT 'Success'
SET #Count = #Count + 1
END
ELSE -- << here
BEGIN
SELECT 'Fail'
END
SET #CurrentRow = #CurrentRow + 1
(2) To count all not null parameters:
SELECT #Count=COUNT(*)
FROM #SPParametersList a
WHERE a.ParameterName IS NOT NULL
To count all null parameters:
SELECT #Count=COUNT(*)
FROM #SPParametersList a
WHERE a.ParameterName IS NULL
Note: if you want to test for NULL / NOT NULL you should use column/#variable IS [NOT] NULL operator and SET ANSI_NULLS must be ON: SET ANSI_NULLS ON.

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]')