Create database scripts where tables have prepopulated data across environment - sql

I have a table named, '[UserTypes]' where Primary id is [uniqueidentifier]. and I have a reference in another table called '[Users]'. Users table has UserTypeId as foreignKey.
CREATE TABLE [UserTypes] (
[Id] [uniqueidentifier] DEFAULT NEWID() PRIMARY KEY,
[UserName] [varchar](100) NOT NULL,
[UserCD] [varchar](40) NOT NULL
GO
INSERT INTO [dbo].[UserTypes]
([UserName], [UserCD])
VALUES
('Administrator','ADMI'),
('NonPrimary','NONP'),
GO
-- ID got generated in [UserTypes] is '80D1EEE7-0BCC-48A7-A741-29A1D8B6E580' for 'ADMI'
CREATE TABLE [Users] (
[Id] [uniqueidentifier] DEFAULT NEWID() PRIMARY KEY,
[UserTypeId] [uniqueidentifier] NOT NULL,
[UserName] [varchar](100) NOT NULL,
CONSTRAINT Users_UserTypeId_UserType_Id FOREIGN KEY (UserTypeId)
REFERENCES UserTypes(Id))
GO
INSERT INTO [dbo].[Users]
([UserTypeId], [UserName])
VALUES
('80D1EEE7-0BCC-48A7-A741-29A1D8B6E580','Kushal Seth')
GO
This '80D1EEE7-0BCC-48A7-A741-29A1D8B6E580' is the userTypeId of 'ADMI' from the userType Table.
My problem is, Suppose, I need to run this script in a new DB, then my ID for 'ADMI' will be different in 'UserTypes' table. and the script will throw error while inserting into the 'Users' table.
One option I have is to declare the variable and select the ID from UserType Table and assign to this variable, and later use that in the insert query of [Users] table.
Is this the only approach? or is there a better way to design such tables. any Design suggestions would really be appreciated.

Suppose, I need to run this script in a new DB, then my ID for 'ADMI' will be different in 'UserTypes' table.
So remove the Guid PK from UserTypes, and make 'UserCD' the primary key.
CREATE TABLE [UserTypes]
(
[UserCD] [varchar](40) NOT NULL PRIMARY KEY,
[UserName] [varchar](100) NOT NULL
)
GO
INSERT INTO [dbo].[UserTypes]
([UserName], [UserCD])
VALUES
('Administrator','ADMI'),
('NonPrimary','NONP')
Which is better in every conceivable way.

Guids are very useful if you have distributed dataservers that must keep uniqueness even when they aren't connected permanently.
But you can do following, as you know the the uusercd is ADMI, you can catch the ID
CREATE TABLE [UserTypes] (
[Id] [uniqueidentifier] DEFAULT NEWID() PRIMARY KEY,
[UserName] [varchar](100) NOT NULL,
[UserCD] [varchar](40) NOT NULL)
INSERT INTO [dbo].[UserTypes]
([UserName], [UserCD])
VALUES
('Administrator','ADMI'),
('NonPrimary','NONP')
GO
-- ID got generated in [UserTypes] is '80D1EEE7-0BCC-48A7-A741-29A1D8B6E580' for 'ADMI'
CREATE TABLE [Users] (
[Id] [uniqueidentifier] DEFAULT NEWID() PRIMARY KEY,
[UserTypeId] [uniqueidentifier] NOT NULL,
[UserName] [varchar](100) NOT NULL,
CONSTRAINT Users_UserTypeId_UserType_Id FOREIGN KEY (UserTypeId)
REFERENCES UserTypes(Id))
INSERT INTO [dbo].[Users]
([UserTypeId], [UserName])
VALUES
((SELECT [Id] FROM [UserTypes] WHERE [UserCD] = 'ADMI'),'Kushal Seth')
SELECT * FROM Users
GO
Id | UserTypeId | UserName
:----------------------------------- | :----------------------------------- | :----------
53f2a6e0-af71-4dab-8a99-821510681a37 | 6acfc89f-f4e2-4ac1-9989-b3a9c062cf0a | Kushal Seth
db<>fiddle here

Related

Replacing a trigger with a stored procedure

I'm trying to replace a trigger statement with a stored procedure since enabled triggers are not allowed when using the tables in microsoft powerapps.
Simplified, I have to tables:
KPI_Dim (KPI_ID [PK] , KPIName, KPIGroup...)
KPICurrent_Fact (KPI_key [FK i.e KPI_Dim[KPI_ID], KPICurrent_ID, KPI_Value...)
Currently, for every new record in KPI_Dim my trigger adds a new row in KPICurrent_Fact with the FK and an autoincremented PK. The rest of the columns e.g. KPI_Value are supposed to be empty.
My simple trigger looks like this:
CREATE TRIGGER [dbo].[trg_insert_newKPI]
ON [dbo].[KPI_Dim]
FOR INSERT AS
INSERT INTO KPICurrent_Fact (KPI_key)
SELECT KPI_ID
FROM INSERTED
Now, I want to create a stored procedure that can achieve exactly the same. I have tried to find a solution myself but I'm new to stored procedures and could not find anything that would replicate a trigger.
I'm using SSMS v.18.4.
Thank you for any suggestions.
EDIT
Added Table creation and insert into statement code.
/* Create KPI_Dim table*/
CREATE TABLE [dbo].[KPI_Dim](
[KPI_ID] [int] IDENTITY(1,1) PRIMARY KEY NOT NULL,
[KPIName] [varchar](200) NOT NULL,
[KPIDescription] [varchar](500) NULL,
[KPIGroup] [varchar](100) NOT NULL,
[KPISubGroup] [varchar](100) NULL,
[KPIOwner] [varchar] (50) NOT NULL,
[DateCreated] DATETIME NULL DEFAULT(GETDATE())
)
/* Example data */
INSERT INTO [dbo].[KPI_Dim]
(
KPIName,
KPIDescription,
KPIGroup,
KPISubGroup,
KPIOwner
)
VALUES
('TestKPIName','testtest','TestGroup', 'TestSubGroup', 'TestOwner');
You can go for OUTPUT Clause and insert into table variable. From the table variable, you can insert into fact table.
CREATE TABLE [dbo].[KPI_Dim](
[KPI_ID] [int] IDENTITY(1,1) PRIMARY KEY NOT NULL,
[KPIName] [varchar](200) NOT NULL,
[KPIDescription] [varchar](500) NULL,
[KPIGroup] [varchar](100) NOT NULL,
[KPISubGroup] [varchar](100) NULL,
[KPIOwner] [varchar] (50) NOT NULL,
[DateCreated] DATETIME NULL DEFAULT(GETDATE())
)
CREATE TABLE dbo.KPI_Fact
(
[KPI_ID] [int] IDENTITY(1,1) PRIMARY KEY NOT NULL,
[KPIDIMID] INT NULL FOREIGN KEY references [dbo].[KPI_Dim]([KPI_ID])
)
DECLARE #inserted table(KPI_DIMID INT)
INSERT INTO [dbo].[KPI_Dim]
(
KPIName,
KPIDescription,
KPIGroup,
KPISubGroup,
KPIOwner
)
OUTPUT inserted.KPI_ID INTO #inserted
VALUES
('TestKPIName','testtest','TestGroup', 'TestSubGroup', 'TestOwner');
INSERT INTO dbo.KPI_Fact([KPIDIMID])
SELECT * FROM #inserted
KPI_ID
KPIDIMID
1
1

How to set ID value from another table

Let's say I have these tables:
CREATE TABLE [dbo].[Users]
(
[User_ID] [int] IDENTITY(1,1)PRIMARY KEY NOT NULL ,
[LogIn] [varchar](100) NULL,
[Pass] [varchar](100) NOT NULL,
)
CREATE TABLE [dbo].[Consecutives]
(
[Consecutives_ID] [int] IDENTITY(1,1) PRIMARY KEY NOT NULL,
[Name] [varchar](100) NULL,
[Value] [int] NOT NULL,
)
I'm being asked to be able to set an edit the User_ID that is going to be used next when adding a new user using the value stated on the Consecutive table.
So if for example the Consecutive value is 50, even if the last user added has the User_ID set to 8 the new user's ID will be 50 and the consecutive updated to 51.
I would do it using a foreign key, but obviously I can't set a primary key to be a foreign key.
I can't find a way to do this.
Can someone help me out?
What you are describing is called a one-to-one relationship.
You create such a relationship by connecting both tables with a foreign key referencing their primary keys (or a unique index).
However, since this is a one-to-one relationship, only the main table actually needs the identity specification on it's primary key.
Your requirement to insert a record to the Users based on an existing record in the Consecutives table seems strange to me. Usually, when you have a one-to-one relationship you populate the related records in both tables in the same transaction.
To create a one-to-one relationship, where Consecutives is the main table, Your DDL should look like this:
CREATE TABLE [dbo].[Consecutives]
(
[Consecutives_ID] [int] IDENTITY(1,1) NOT NULL,
[Name] [varchar](100) NULL,
[Value] [int] NOT NULL,
CONSTRAINT PK_Consecutives PRIMARY KEY (Consecutives_ID)
);
CREATE TABLE [dbo].[Users]
(
[User_ID] [int] NOT NULL,
[LogIn] [varchar](100) NULL,
[Pass] [varchar](100) NOT NULL,
CONSTRAINT PK_Users PRIMARY KEY (User_ID),
CONSTRAINT FK_Users_Consecutives FOREIGN KEY (User_ID) REFERENCES [dbo].[Consecutives]([Consecutives_ID])
);
Please note I've removed the identity specification from the User_ID column, and also changed the way the primary key is declared so that I could name it manually.
Naming constraints is best practice since if you ever need to change them it's much simpler when you already know their names.
Now, to insert a single record to both tables in the same transaction you can create a stored procedure like this:
CREATE PROCEDURE InsertUser
(
#Name varchar(100),
#Value int,
#LogIn varchar(100),
#Pass varchar(100)
)
AS
DECLARE #Consecutives AS TABLE
(
Id int
);
BEGIN TRY
BEGIN TRANSACTION
INSERT INTO [dbo].[Consecutives] ([Name], [Value])
OUTPUT Inserted.Consecutives_ID INTO #Consecutives
VALUES (#Name, #Value)
INSERT INTO [dbo].[Users] ([User_ID], [LogIn], [Pass])
SELECT Id, #Login, #Pass
FROM #Consecutives
COMMIT TRANSACTION
END TRY
BEGIN CATCH
IF ##TRANCOUNT > 0
ROLL BACK TRANSACTION
END CATCH
GO
and execute it like this:
EXEC InsertUser 'Zohar Peled', 1, 'Zohar', 'Peled'
You can see a live demo on rextester. (Please note that rextester doesn't allow using transactions so the try...catch and transaction parts are removed from the demo there)
Have you ever tried set identity insert on? This link may help you. To use the identity insert, the user needs some alter table permissions.

SQL Server : How to combine multiple database into one database?

From my original database, I made changes to some tables with columns in the table, I want to merge them into a single database. New database just add some table and old table add some columns.
How to merge multiple database into one database?
SQL example:
CREATE TABLE [dbo].[Item]
(
[ItemID] [nchar](10) NOT NULL,
[Money] [bigint] NOT NULL,
[ItemName] [bigint] NOT NULL,
[MoneyType] [bigint] NOT NULL,
CONSTRAINT [PK_Item]
PRIMARY KEY CLUSTERED ([ItemID] ASC) ON [PRIMARY]
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[Account]
(
[Index] [int] IDENTITY(1,1) NOT NULL,
[AccountID] [nchar](10) NOT NULL,
[AccountName] [int] NOT NULL,
[ItemList] [int] NOT NULL,
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[Money]
(
[AccountID] [nchar](10) NOT NULL,
[Money] [bigint] NOT NULL,
[MoneyType] [bigint] NOT NULL,
CONSTRAINT [PK_Money]
PRIMARY KEY CLUSTERED ([AccountID] ASC) ON [PRIMARY]
) ON [PRIMARY]
GO
-> Nick.McDermaid: use the schema compare tool in Visual Studio (various free editions) which will create a change script!
This will combine them onto DBCombined.Account if the Account table does NOT exist yet: the SELECT INTO code creates the target table. You would then need to add any indexes from the original tables. Also, "SELECT *" should really be broken out, listing each field, because if you have an ID field it will contain duplicates. Better to leave ID off during the insert and then go back and add an identity column.
USE DBCombined
GO
SELECT *
INTO Account
FROM (
SELECT *
FROM DB1.dbo.Account
UNION ALL
SELECT *
FROM DB2.dbo.Account
) Acct

Update PK columns in table having clustered keys

I have a database with tables that have clustered primary keys. I believe the term I picked up on is use of a Natural Key. The frontend to the SQL database is programmed to affect changes to all related foreign key tables for the 3,000 selected values which I want to modify. It takes about 13 seconds per change. I have a need to do this in a much shorter timeframe if possible.
The reason for doing this is prep work to migrate to a new CMMS program.
I found reference for use of ON UPDATE CASCADE, but I am not certain this applies.
Among many references, I used the following:
https://social.technet.microsoft.com/Forums/sqlserver/it-IT/23294919-3e6a-4146-a70d-66fa155ed1b3/update-primary-key-column-in-sql-server?forum=transactsql
An example of 2 of the 15 tables having the same named [EQNUM] column follows. Table A is the table that is first modified using the frontend. I left out many columns for each table:
CREATE TABLE A
(
[EQNUM] [varchar](30) NOT NULL,
CONSTRAINT [PK_A] PRIMARY KEY CLUSTERED ([EQNUM] ASC)
)
GO
SET ANSI_PADDING OFF
GO
CREATE TABLE B
(
[EQNUM] [varchar](30) NOT NULL,
[ColA] [varchar](10) NOT NULL,[ColB] [datetime] NOT NULL,
[ColC] [varchar](30) NOT NULL, [ColD] [varchar](30) NOT NULL,
[ColE] [varchar](30) NOT NULL, [ColF] [varchar](30) NOT NULL,
[ColG] [varchar](11) NOT NULL,[ColH] [varchar](10) NOT NULL,
[ColI] [datetime] NOT NULL,[ColJ] [varchar](15) NOT NULL,
[ColK] [int] NULL,
CONSTRAINT [PK_B]
PRIMARY KEY CLUSTERED ([EQNUM] ASC,
[ColA] ASC,[ColB] ASC,[ColC] ASC,[ColD] ASC,[ColE] ASC,
[ColF] ASC,[ColG] ASC,[ColH] ASC,[ColI] ASC,[ColJ] ASC)
)
An example of 1 of 4 sets of UPDATE queries, for which I believe the added first and last ALTER TABLE lines would allow me to affect the update:
ALTER TABLE A NOCHECK CONSTRAINT [PK_EQUIP]
UPDATE A
SET [EQNUM] = REPLACE([EQNUM],'-B','-B0')
WHERE [EQNUM] LIKE '%-A[1-9][0-5][0-9]-%' OR
[EQNUM] LIKE '%-A[1-9][A-F][0-5][0-9]-%' OR
ALTER TABLE A CHECK CONSTRAINT [PK_EQUIP]
ALTER TABLE A NOCHECK CONSTRAINT [PK_B]
UPDATE B
SET [EQNUM] = REPLACE([EQNUM],'-B','-B0')
WHERE [EQNUM] LIKE '%-A[1-9][0-5][0-9]-%' OR
[EQNUM] LIKE '%-A[1-9][A-F][0-5][0-9]-%' OR
ALTER TABLE A CHECK CONSTRAINT [PK_B]
Is it this simple, or am I missing something? Is there a better way?

How do I insert into two tables all at once in a stored procedure? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How can I INSERT data into two tables simultaneously in SQL Server?
Doing a project for school so any help would be great thank you!
I have two tables - how do I insert into two tables? So both tables are linked.
First table is called Customer with primary key called CID that auto increments
CREATE TABLE [dbo].[Customer](
[CID] [int] IDENTITY(1,1) NOT NULL,
[LastName] [varchar](255) NOT NULL,
[FirstName] [varchar](255) NOT NULL,
[MiddleName] [varchar](255) NULL,
[EmailAddress] [varchar](255) NOT NULL,
[PhoneNumber] [varchar](12) NOT NULL
CONSTRAINT [PK__CInforma__C1F8DC5968DD69DC] PRIMARY KEY CLUSTERED
(
And a second table called Employment that has a foreign key linked to the parent table
CREATE TABLE [dbo].[Employment](
[EID] [int] IDENTITY(1,1) NOT NULL,
[CID] [int] NOT NULL,
[Employer] [varchar](255) NOT NULL,
[Occupation] [varchar](255) NOT NULL,
[Income] [varchar](25) NOT NULL,
[WPhone] [varchar](12) NOT NULL,
CONSTRAINT [PK__Employme__C190170BC7827524] PRIMARY KEY CLUSTERED
(
You need to do something like this:
DECLARE #NewID INT
INSERT INTO Customer(LastName,FirstName,......) VALUES(Value1, Value2, .....)
SELECT #NewID = SCOPE_IDENTITY()
INSERT INTO Employment(CID,Employer,.....) VALUES(#NewID, ValueA,..........)
SCOPE_IDENTITY: Returns the last identity value inserted into an identity column in the same scope. A scope is a module: a stored procedure, trigger, function, or batch. Therefore, two statements are in the same scope if they are in the same stored procedure, function, or batch.