I created a table type:
CREATE TYPE int_array AS TABLE (n INT NOT NULL)
and want to use it to insert several rows in a single procedure into the following table:
CREATE TABLE myTable
(
Id_SecondTable INT NOT NULL,
Id_ThirdTable INT NOT NULL,
CONSTRAINT PK_myTable
PRIMARY KEY (Id_SecondTable, Id_ThirdTable),
CONSTRAINT FK_Id_SecondTable
FOREIGN KEY (Id_SecondTable) REFERENCES SecondTable (Id),
CONSTRAINT FK_Id_ThirdTable
FOREIGN KEY (Id_ThirdTable) REFERENCES ThirdTable (Id)
)
My procedure is as follows:
CREATE PROCEDURE test
(#value INT,
#array int_array READONLY)
AS
BEGIN
INSERT INTO myTable
VALUES (Id_SecondTable, Id_ThirdTable) (#value, SELECT n FROM #array)
END
What am I doing wrong?
You can't mix a scalar value and select statement in your insert. You need to make the scalar value a column in the select instead. Like this.
CREATE PROCEDURE test(
#value INT,
#array int_array readonly
)
AS
BEGIN
INSERT INTO myTable
(
Id_SecondTable
, Id_ThirdTable
)
SELECT #value
, n
FROM #array
END
Related
I have temp table each time store 100 values based on a specific condition.
I need Slno as 1,2,3,4 ...100 each time query executes .
If I use below syntax's, the 'Slno' is taking some other numbers
create table #temptable
(Slno INT IDENTITY(1,1) NOT NULL ,
Name varchar(50)
)
create table #temptable
(Slno int IDENTITY(1,1) PRIMARY KEY ,
Name varchar(50)
)
Please help if there is a way out without using Rank()?
You need to create an IDENTITY column as follows:
Syntax:
CREATE TABLE (
ID_column INT NOT NULL IDENTITY(1,1) PRIMARY KEY,
...
);
It should be
Identity(seed,increment)
Here you go:
CREATE TABLE #temptable
(Slno INT NOT NULL IDENTITY(1,1) PRIMARY KEY,
Name varchar(50)
)
Example:
INSERT INTO #temptable (Name) Values ('ABC')
INSERT INTO #temptable (Name) Values ('ABhshC')
INSERT INTO #temptable (Name) Values ('ABQRAC')
INSERT INTO #temptable (Name) Values ('ABhsAERAYRHAERhC')
SELECT * FROM #temptable
Results:
Slno Name
1 ABC
2 ABhshC
3 ABQRAC
4 ABhsAERAYRHAERhC
For example, I have 2 tables
Create table Authorized
(D_ID char(5), MNUM char(5), primary key(D_ID,MNUM),
foreign key(D_ID) REFERENCES Distributor(D_ID),
foreign key(MNUM) REFERENCES Model(MNUM));
Create table Orders
(ORDNO char(8), D_ID char(5), MNUM char(5),
Qty int, Date date, primary key (ORDNO,D_ID,MNUM),
foreign key(MNUM) REFERENCES Model(MNUM),
foreign key(D_ID) REFERENCES Distributor(D_ID));
INSERT INTO Authorized VALUES ('D0003', 'M0001');
INSERT INTO Authorized VALUES ('D0003', 'M0003');
How to I make sure that insert statement to the order table is restricted to D_ID that is authorized? Like if the statement is
INSERT INTO Orders VALUES
('20161232', 'D0003','M0002',2, '2016-12-22');
How do you prevent this insert statement from going through? AS M0002 is not authorized
You can create a Scalar function and use it in your table as:
CREATE FUNCTION IsAuthorized
(
#Value CHAR(5) --I think you mean "MNUM" column here
)
RETURNS BIT
AS
BEGIN
DECLARE #Result BIT = 0;
IF EXISTS (SELECT 1 FROM Authorized WHERE D_ID = #Value)
SET #Result = 1;
RETURN(#Result);
END;
GO
Here is how to use it in the table:
Create table Orders(
ORDNO char(8),
D_ID char(5) CONSTRAINT CHK_IsAuthorized CHECK(IsAuthorized(D_ID) = 1),
MNUM char(5),
...
...
Why does SCOPE_IDENTITY() return NULL after inserting a row in the ComponentAssociation table (as ##IDENTITY returns the right Id)
while SCOPE_IDENTITY() returns the right Id after inserting a row in the CustomerProjectAssociation table ?
The two association tables are created the same way.
Here is an extract of the table creation script:
-- Creating table 'CustomerProjectAssociation'
CREATE TABLE [dbo].[CustomerProjectAssociation]
(
[Id] int IDENTITY(1,1) NOT NULL,
[CustomerId] int NOT NULL,
[ProjectId] int NOT NULL,
[CreationDate] datetime NOT NULL CONSTRAINT DF_CustomerProjectAssociation_CreationDate DEFAULT (SYSUTCDATETIME()),
[LastModificationDate] datetime NOT NULL CONSTRAINT DF_CustomerProjectAssociation_ModificationDate DEFAULT (SYSUTCDATETIME())
);
GO
-- Creating table 'ComponentAssociation'
CREATE TABLE [dbo].[ComponentAssociation]
(
[Id] int IDENTITY(1,1) NOT NULL,
[EcuId] int NOT NULL,
[CreationDate] datetime NOT NULL CONSTRAINT DF_ComponentAssociation_CreationDate DEFAULT (SYSUTCDATETIME()),
[LastModificationDate] datetime NOT NULL CONSTRAINT DF_ComponentAssociation_ModificationDate DEFAULT (SYSUTCDATETIME()),
[ComponentId] int NOT NULL
);
GO
-- Creating primary key on [Id] in table 'CustomerProjectAssociation'
ALTER TABLE [dbo].[CustomerProjectAssociation]
ADD CONSTRAINT [PK_CustomerProjectAssociation]
PRIMARY KEY CLUSTERED ([Id] ASC);
GO
-- Creating primary key on [Id] in table 'ComponentAssociation'
ALTER TABLE [dbo].[ComponentAssociation]
ADD CONSTRAINT [PK_ComponentAssociation]
PRIMARY KEY CLUSTERED ([Id] ASC);
GO
And here are two queries executed on the database from SQL Server Management Studio:
INSERT [dbo].[CustomerProjectAssociation]([CustomerId], [ProjectId])
VALUES (1, 2)
SELECT
[RowCount] = ##RowCount,
[##IDENTITY] = ##IDENTITY,
[SCOPE_IDENTITY] = SCOPE_IDENTITY()
Result:
RowCount ##IDENTITY SCOPE_IDENTITY
1 24 24
INSERT [dbo].[ComponentAssociation]([EcuId], [ComponentId])
VALUES(1, 2)
SELECT
[RowCount] = ##RowCount,
[##IDENTITY] = ##IDENTITY,
[SCOPE_IDENTITY] = SCOPE_IDENTITY()
Result:
RowCount ##IDENTITY SCOPE_IDENTITY
1 613 NULL
OK, the issue is solved.
Found the solution here: error when inserting into table having instead of trigger from entity data framework
I added the following select statement at the end of the instead of insert,update trigger returning all the computed columns:
select [Id], [CreationDate], [LastModificationDate] from {0}.[dbo].[ComponentAssociation] where ##ROWCOUNT > 0 and Id = scope_identity()
midx column is the primary key that using auto increment (identity 1,1).
When I try to insert data using this query, that is a problem:
Insert into coordinfo(mdate, X, Y, lat, lon)
values (GETDATE(), 12344, 334, 34.775, 123.554);
I want to increase the midx by automatically without entering the primary key.
Thanks!
Normally a primary key column cannot be null, since it has to be a clustered index on the table.
In order to get the effect you want, you should create a keys table with a non-null identity column.
If your table is defined as follows, with an insert trigger, your insert DML will yield an auto-generated value for midx:
CREATE TABLE keyTable
(
[key] int identity(1,1) primary key not null,
date datetime
)
CREATE TRIGGER myTable_increment_midx ON myTable
after INSERT
AS
BEGIN
DECLARE #key int
INSERT INTO keyTable (date) values (getdate())
SET #key = ##IDENTITY
UPDATE t
set t.midx = #key
FROM mytable t join INSERTED i on i.mdate = t.mdate and ...
END
CREATE TABLE myTable
(
mdate DATETIME,
udate DATETIME,
midx INT PRIMARY KEY NULL, --again, you shouldn't be allowed to do this
X INT,
Y INT,
lat DECIMAL(9, 6),
lon DECIMAL(9, 6)
)
you can use compete column:
ALTER TABLE coordinfo ADD midx AS idx*100
I have created a scalar function in SQL Server 2008 and the same I am referring in a computed column in few of my tables. Now I want to alter the function without dropping the table. But it throws an error:
Cannot ALTER 'dbo.GetStatus' because it is being referenced by object
'Order'.
Is is possible to alter the function? Or do I drop and create all dependable table first and then alter the function?
Here is my function:
CREATE FUNCTION [dbo].[GetStatus]
(
#FromDate datetime,
#ToDate datetime
)
RETURNS tinyint
AS
BEGIN
declare #ret tinyint;
if(#FromDate<=GETDATE() and (#ToDate>=GETDATE() or #ToDate is null))
set #ret= 1
else
set #ret= 0
return #ret
END
And it is referring in a table:
CREATE TABLE [dbo].[Order](
[Id] [int] IDENTITY(1,1) NOT NULL,
[Name] [varchar](200) NOT NULL,
[EffectiveFromDate] [datetime] NOT NULL,
[EffectiveToDate] [datetime] NULL,
[Status] AS ([dbo].[GetStatus]([EffectiveFromDate],[EffectiveToDate]))
)
This is by design. You should first drop all defaults/constraints, then alter your function and the add those constraints back. No need to drop the tables.
But you can work around this by the following trick:
add intermediate function that will call your actual function;
alter computed columns to call intermediate function instead of actual.
Example:
CREATE FUNCTION dbo.fnActual ( #p INT )
RETURNS INT
AS
BEGIN
RETURN #p + 1
END
GO
CREATE FUNCTION dbo.fnIntermediate ( #p INT )
RETURNS INT
AS
BEGIN
RETURN dbo.fnActual(#p)
END
GO
CREATE TABLE TestTable(id INT, fn AS dbo.fnIntermediate(id))
GO
Insert some value:
INSERT INTO dbo.TestTable VALUES ( 1 )
SELECT * FROM dbo.TestTable --selects 2
--throws exception
ALTER FUNCTION dbo.fnIntermediate ( #p INT )
RETURNS INT
AS
BEGIN
RETURN dbo.fnActual(#p)
END
GO
--succseeds
ALTER FUNCTION dbo.fnActual ( #p INT )
RETURNS INT
AS
BEGIN
RETURN #p + 2
END
GO
SELECT * FROM dbo.TestTable --selects 3
ALTER TABLE [dbo].[Order]
DROP COLUMN [Status]
GO
ALTER FUNCTION [dbo].[GetStatus] ...
GO
ALTER TABLE [dbo].[Order]
ADD [Status] AS ([dbo].[GetStatus]([EffectiveFromDate],[EffectiveToDate]))
GO
or even
ALTER TABLE [dbo].[Order]
DROP COLUMN [Status]
GO
ALTER TABLE [dbo].[Order]
ADD [Status] AS CAST(CASE WHEN [EffectiveFromDate] <= GETDATE() AND ([EffectiveToDate] >= GETDATE() OR [EffectiveToDate] IS NULL) THEN 1 ELSE 0 END as tinyint)
GO