How to use output variable in insert query - tsql

I am inserting records from our crm to our erp. The phone table uses a identity column from the people table. I need to insert the people record and capture the value in the PersonId which is an identity column and then use that PersonId as the key to insert records to the Phone table. I get the error:
Msg 137, Level 16, State 1, Line 16
Must declare the scalar variable "#IdentityID".
Msg 137, Level 16, State 1, Line 17
Must declare the scalar variable "#IdentityID".
--IdentityTable
CREATE TABLE [dbo].[People](
[People_ID] [int] NOT NULL,
[text] [nvarchar](50) NULL,
[PersonId] [int] IDENTITY(1,1) NOT NULL
) ON [PRIMARY]
--Phone
CREATE TABLE [dbo].[Phone](
[PersonId] [int] NOT NULL,
[text] [nvarchar](50) NULL,
[Number] [nchar](10) NULL
) ON [PRIMARY]
declare #IdentityID table (PersonId int);
INSERT INTO [Bridge].[dbo].[People]
([People_ID]
,[text])
output Inserted.PersonId into #IdentityID
VALUES
(3,'row1'),
(4,'row2');
INSERT INTO [Bridge].[dbo].[Phone]
(PersonId
,[text]
,[Number])
VALUES
(#IdentityID,'row1'),
(#IdentityID,'row2');
Print 'IdentityID' + #IdentityID
Msg 137, Level 16, State 1, Line 16
Must declare the scalar variable "#IdentityID".
Msg 137, Level 16, State 1, Line 17
Must declare the scalar variable "#IdentityID".

Output will be to tablevariable you can use as below:
declare #IdentityID table (PersonId int);
INSERT INTO [dbo].[People]
([People_ID]
,[text])
output Inserted.PersonId into #IdentityID(PersonId)
VALUES
(3,'row1'),
(4,'row2');
INSERT INTO [dbo].[Phone]
(PersonId
,[text]
,[Number])
select PersonId,'row1', 1 from #IdentityID
union all select PersonId,'row2', 2 from #IdentityID
select * from #IdentityID

Related

Postgres: insert multiple rows on conflict update not working

I am trying to insert multiple rows into a table, and, in case of conflict, simply update them. What am I doing wrong?
insert into segments(id, departure_hour)
values
(1153, 2),
(1156, 4),
(1154, 2)
on conflict do update set
departure_hour = c.departure_hour
from (values
(1153, 2),
(1156, 4),
(1154, 2))
as c(id, departure_hour)
where c.id = segments.id
As requested, here is my table definition:
CREATE TABLE segments (
id SERIAL PRIMARY KEY,
route_id integer NOT NULL REFERENCES routes(id),
origin_id integer NOT NULL REFERENCES stops(id),
destination_id integer NOT NULL REFERENCES stops(id),
price integer DEFAULT 0,
departure_day integer NOT NULL,
departure_hour integer NOT NULL,
departure_minute integer NOT NULL,
arrival_day integer NOT NULL,
arrival_hour integer NOT NULL,
arrival_minute integer NOT NULL,
hidden boolean NOT NULL DEFAULT false,
deleted boolean NOT NULL DEFAULT false,
CONSTRAINT unique_origin_destination_per_route UNIQUE (route_id, origin_id, destination_id)
);
And here is my error:
ERROR: syntax error at or near "from"
LINE 1: ...pdate set departure_hour = c.departure_hour from (valu...
You don't need the from part in order to be able to reference the values to update.
insert into segments(id, departure_hour)
values
(1153, 2),
(1156, 4),
(1154, 2)
on conflict do update set
departure_hour = excluded.departure_hour;

What is the code for a T-SQL check constraint?

I want to add a check clause to this table so that:
IF a transaction enters a value for the diastolicBloodPressure
THEN the transaction must also insert a value for the systolicBloodPressure.
CREATE TABLE "Constraint-BloodPressure".Patient
(
patientNr int NOT NULL,
diastolicBloodPressure smallint,
systolicBloodPressure smallint,
CONSTRAINT Patient_PK PRIMARY KEY(patientNr)
)
Is this correct?
CONSTRAINT CHK_BloodPressure CHECK (diastolicBloodPressure >0 AND systolicBloodPressure >0 )
You did not specify, whether your table would accept NULL-values and how you would deal with them.
Due to the kind of data, my suggestion was this:
CREATE TABLE dbo.TestCheck
(
patientNr INT NOT NULL CONSTRAINT PK_TestCheck PRIMARY KEY
,diastolicBloodPressure smallint NOT NULL
,systolicBloodPressure smallint NOT NULL
,CONSTRAINT chk_TestCheck_MustEnterBoth CHECK(diastolicBloodPressure BETWEEN 0 AND 250 AND systolicBloodPressure BETWEEN 0 AND 250)
);
--The table will not accept NULL-values and it will force the entered values to keep within realistic borders.
--Instead of smallint you might use tinyint, which is bordered between 0 and 255 by definition.
--Try the following:
INSERT INTO dbo.TestCheck VALUES(1,100,110);
GO
INSERT INTO dbo.TestCheck VALUES(2,100,NULL);
GO
INSERT INTO dbo.TestCheck VALUES(3,NULL,NULL);
GO
INSERT INTO dbo.TestCheck VALUES(4,-1,1000);
GO
SELECT * FROM dbo.TestCheck;
--Only the first insert will succeed, all the other attempts fill fail
--Clean-Up Carefull with real data...
GO
DROP TABLE dbo.TestCheck;
Not sure what database system you are using. On SQL Server 2014 I am require specify "NULL" or "NOT NULL". So my create table statement with the check constraint and insert statements looks like this...
IF OBJECT_ID('tempdb.dbo.#Patient', 'U') IS NOT NULL
DROP TABLE #Patient;
CREATE TABLE #Patient
(
patientNr INT NOT NULL
, diastolicBloodPressure SMALLINT NULL
, systolicBloodPressure SMALLINT NULL
, CONSTRAINT Patient_PK
PRIMARY KEY (patientNr)
, CHECK ((
diastolicBloodPressure IS NOT NULL
AND systolicBloodPressure IS NOT NULL
)
OR (
diastolicBloodPressure IS NULL
AND systolicBloodPressure IS NULL
)
)
);
INSERT INTO #Patient VALUES (1, NULL, NULL);
INSERT INTO #Patient VALUES (2, 120, NULL);
INSERT INTO #Patient VALUES (3, NULL, 80);
INSERT INTO #Patient VALUES (4, 120, 80);
The first and last insert statements work and the middle two fail.
If you want to force both fields to have a value, then you need to check for null values. If you don't, then your current check will allow entry of just the patientNbr or just one value.
CREATE TABLE dbo.Patient
(
patientNr int NOT NULL,
diastolicBloodPressure smallint,
systolicBloodPressure smallint,
CONSTRAINT Patient_PK PRIMARY KEY(patientNr),
CONSTRAINT CHK_BloodPressure CHECK (ISNULL(diastolicBloodPressure, 0) > 0 AND ISNULL(systolicBloodPressure, 0) > 0 )
);
GO
-- Valid
INSERT INTO dbo.Patient VALUES (1, 120, 80);
GO
-- Invalid
INSERT INTO dbo.Patient VALUES (2, 120, 0);
GO
-- Invalid
INSERT INTO dbo.Patient VALUES (3, 0, 80);
GO
-- Invalid
INSERT INTO dbo.Patient (patientNr, diastolicBloodPressure) VALUES (4, 120);
GO
-- Invalid
INSERT INTO dbo.Patient (patientNr) VALUES (5);
GO

How to DROP and CREATE a table in SQL Server 2016 Stored Procedure

I am trying to create a stored procedure that will drop a table and then create a new table with the same name.
However, when I right clicked on the table and did Script Table as ... DROP and CREATE To ... New Query Editor Window and then copied the script into a blank stored procedure, it wouldn't let me create the procedure because
There is already an object named 'MyTable' in the database
What should I do?
NOTE: the new table will not be the same structure as the old table. I make some transformations using other stored procedures to the table, so at the end, I want to drop it and create from scratch.
Here is the actual script:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[spDropAndCreate]
AS
BEGIN
SET NOCOUNT ON;
IF OBJECT_ID ('dbo.MyTable','U') IS NOT NULL
DROP TABLE [dbo].[MyTable]
CREATE TABLE [dbo].[MyTable]
(
[ID] [int] IDENTITY(1,1) NOT NULL,
[Col1] [nvarchar](50) NULL,
[Col2] [nvarchar](50) NULL,
[Col3] [nvarchar](50) NULL,
[Col4] [nvarchar](50) NULL,
[Col5] [nvarchar](50) NULL,
[Col6] [nvarchar](50) NULL,
[Col7] [nvarchar](50) NULL,
[Col8] [nvarchar](50) NULL,
[Col9] [nvarchar](50) NULL,
[Col10] [nvarchar](50) NULL
)
GO
END
Here is the error message:
Msg 102, Level 15, State 1, Procedure spDropAndCreate, Line 17 [Batch Start Line 9]
Incorrect syntax near 'MyTable'
Msg 2714, Level 16, State 6, Line 35
There is already an object named 'MyTable' in the database
Msg 102, Level 15, State 1, Line 156
Incorrect syntax near 'END'
You need to remove the GO that is within the BEGIN and END block. GO is a batch separator which is like telling the block to execute before it's even ended. Check out this previous post for more info.
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[spDropAndCreate]
AS
BEGIN
SET NOCOUNT ON;
IF OBJECT_ID ('dbo.MyTable','U') IS NOT NULL
DROP TABLE [dbo].[MyTable]
CREATE TABLE [dbo].[MyTable]
(
[ID] [int] IDENTITY(1,1) NOT NULL,
[Col1] [nvarchar](50) NULL,
[Col2] [nvarchar](50) NULL,
[Col3] [nvarchar](50) NULL,
[Col4] [nvarchar](50) NULL,
[Col5] [nvarchar](50) NULL,
[Col6] [nvarchar](50) NULL,
[Col7] [nvarchar](50) NULL,
[Col8] [nvarchar](50) NULL,
[Col9] [nvarchar](50) NULL,
[Col10] [nvarchar](50) NULL
)
END
Add a GO after the DROP TABLE statement to separate the batches.
This won’t work for a procedure though. Instead uses exists when sys objects.
If exists(select 1 from sys.objects where name = 'mytable')
drop mytable

Change database dynamically in SQL Server using a stored procedure

I have a question about SQL Server: how to change database name dynamically and use one select and insert statment to load data using a stored procedure.
How to change the database name with insert and select statement while table data loading into another table?
Here each database name related table load into with in the database name related target table.
i.e database: test and source table: emp target table is :emptarget here emp table records load into emptarget similar to another databases
Database names information maintain one table.
USE [test]
GO
CREATE TABLE [dbo].[databaseinformation]
(
[id] [int] NULL,
[databasename] [varchar](50) NULL
) ON [PRIMARY]
GO
INSERT [dbo].[databaseinformation] ([id], [databasename])
VALUES (1, N'test'), (2, N'test1')
GO
Table1 : source : emp and datbasename: test
USE [test]
CREATE TABLE [dbo].[emp]
(
[id] [int] NULL,
[name] [varchar](50) NULL,
[sal] [int] NULL
)
INSERT [dbo].[emp] ([id], [name], [sal])
VALUES (19, N'hd', 40), (1, N'g', 10),
(9, N'dk', 90), (80, N'dhe', 80)
GO
Target table : emptarget and databasename: test
USE [test]
CREATE TABLE [dbo].[emptarget]
(
[id] [int] NULL,
[name] [varchar](50) NULL,
[sal] [int] NULL
)
----table 2: emp and databasename: test1
USE [test]
CREATE TABLE [dbo].[emp]
(
[id] [int] NULL,
[name] [varchar](50) NULL,
[sal] [int] NULL
)
INSERT [dbo].[emp] ([id], [name], [sal])
VALUES (50, N'kl', 80), 39, N'abc', 10)
go
Target table : emptarget and databasename: test1
USE [test1]
CREATE TABLE [dbo].[emptarget]
(
[id] [int] NULL,
[name] [varchar](50) NULL,
[sal] [int] NULL
)
Finally need to load data like below
Database: test and table : emptarget
id |name |sal
19 |hd |40
1 |g |10
9 |dk |90
80 |dhe |80
Database: test1 and table : emptarget
id |name |sal
50 |kl |80
39 |abc |10
I tried like below
USE [test]
GO
insert into emptarget
select * from emp
USE [test1]
GO
insert into emptarget
select * from emp
Here I do not want run two queries separately. I need to run querying using single select and insert statement to load data correspong tables with databases.
Please tell me how to write query to achive this task in SQL Server
Actually I have no idea about why you don't do this.
insert into test.emptarget select * from test.emp;
insert into test1.emptarget select * from test1.emp;
So I think you just want one query to do this.
create procedure emptoemptarget (#DBName nvarchar(10))
as
begin
declare #sql nvarchar(1000)
set #sql = 'insert into ' + #DBName + '.emptarget select * from ' + #DBName + '.emp'
exec (#sql)
end
select dbo.emptoemptarget(name) from sys.databases where name in ('test','test1')

sql drop primary key from temp table

I want to create e temp table using select into syntax. Like:
select top 0 * into #AffectedRecord from MyTable
Mytable has a primary key. When I insert record using merge into syntax primary key be a problem. How could I drop pk constraint from temp table
The "SELECT TOP (0) INTO.." trick is clever but my recommendation is to script out the table yourself for reasons just like this. SELECT INTO when you're actually bringing in data, on the other hand, is often faster than creating the table and doing the insert. Especially on 2014+ systems.
The existence of a primary key has nothing to do with your problem. Key Constraints and indexes don't get created when using SELECT INTO from another table, the data type and NULLability does. Consider the following code and note my comments:
USE tempdb -- a good place for testing on non-prod servers.
GO
IF OBJECT_ID('dbo.t1') IS NOT NULL DROP TABLE dbo.t1;
IF OBJECT_ID('dbo.t2') IS NOT NULL DROP TABLE dbo.t2;
GO
CREATE TABLE dbo.t1
(
id int identity primary key clustered,
col1 varchar(10) NOT NULL,
col2 int NULL
);
GO
INSERT dbo.t1(col1) VALUES ('a'),('b');
SELECT TOP (0)
id, -- this create the column including the identity but NOT the primary key
CAST(id AS int) AS id2, -- this will create the column but it will be nullable. No identity
ISNULL(CAST(id AS int),0) AS id3, -- this this create the column and make it nullable. No identity.
col1,
col2
INTO dbo.t2
FROM t1;
Here's the (cleaned up for brevity) DDL for the new table I created:
-- New table
CREATE TABLE dbo.t2
(
id int IDENTITY(1,1) NOT NULL,
id2 int NULL,
id3 int NOT NULL,
col1 varchar(10) NOT NULL,
col2 int NULL
);
Notice that the primary key is gone. When I brought in id as-is it kept the identity. Casting the id column as an int (even though it already is an int) is how I got rid of the identity insert. Adding an ISNULL is how to make a column nullable.
By default, identity insert is set to off here to this query will fail:
INSERT dbo.t2 (id, id3, col1) VALUES (1, 1, 'x');
Msg 544, Level 16, State 1, Line 39
Cannot insert explicit value for identity column in table 't2' when IDENTITY_INSERT is set to OFF.
Setting identity insert on will fix the problem:
SET IDENTITY_INSERT dbo.t2 ON;
INSERT dbo.t2 (id, id3, col1) VALUES (1, 1, 'x');
But now you MUST provide a value for that column. Note the error here:
INSERT dbo.t2 (id3, col1) VALUES (1, 'x');
Msg 545, Level 16, State 1, Line 51
Explicit value must be specified for identity column in table 't2' either when IDENTITY_INSERT is set to ON
Hopefully this helps.
On a side-note: this is a good way to play around with and understand how select insert works. I used a perm table because it's easier to find.