Insert data from one table to another table while the target table has a primary key - sql

In SQL Server I have a table as RawTable (temp) which gets fed by a CVS, let's say it has 22 columns in it. Then, I need to copy existing records (ONLY FEW COLUMNs NOT ALL) into another table as Visitors which is not temporary table.
Visitor table has an ID column as INT and that is primary key and incremental.
RawData table
id PK, int not null
VisitorDate Varchar(10)
VisitorTime Varchar(11)
Visitors table
VisitorID, PK, big int, not null
VisitorDate, Varchar(10), null
VisitorTime Varchar(11), null
So I did:
insert into [dbo].[Visitors] ( [VisitorDate], [VisitorTime])
select [VisitorDate], [VisitorTime]
from RawTable /*this is temp table */
Seems SQL Server doesn't like this method so it throws
Msg 515, Level 16, State 2, Line 1
Cannot insert the value NULL into column 'VisitorID', table 'TS.dbo.Visitors'; column does not allow nulls. INSERT fails. The statement has been terminated.
How can I keep Sql Server not to complain about the primary key? this column as you know better will be fed by sql server itself.
Any idea?

Just because your visitors table has an ID column that is the primary key doesn't mean that the server will supply your ID values for you. if you want SQL to provide the ID's then you need to alter the table definition and make the visitorsId column an IDENTITY column.
Otherwise, you can psuedo-create these id's during the insert with the ROW_NUMBER function -
DECLARE #maxId INT;
SELECT #maxId = (SELECT MAX(visitorsId) FROM dbo.visitors);
INSERT INTO [dbo].[Visitors] ( [visitorsId],[VisitorDate], [VisitorTime])
SELECT #maxId + ROW_NUMBER() OVER (ORDER BY visitorDate), [VisitorDate], [VisitorTime]
from RawTable /*this is temp table */

Related

How to select from table A and then insert selected id inside table B with one query?

I'm trying to implement a very basic banking system.
the goal is to have different types of transactions ( deposit, withdraw, transfer ) inside a table and refer to them as IDs inside transaction tables.
CREATE TABLE transaction_types (
id INTEGER AUTO_INCREMENT PRIMARY KEY,
name VARCHAR UNIQUE NOT NULL
)
CREATE TABLE transactions (
id INTEGER AUTO_INCREMENT PRIMARY KEY,
type_id INTEGER NOT NULL,
amount FLOAT NOT NULL
)
What I'm trying to accomplish is:
When inserting into transactions table no record can have an invalid type_id ( type_id should exist in transaction_types table )
First of all get type_id from transaction_types table and then insert inside transactions table, with one query ( if it's possible, I'm fairly new )
I'm using Node.js/Typescript and PostgreSQL, any help is appreciated a lot.
For (1): modify Transactions table definition by adding REFERENCES transaction_types(id) to the end of the type_id column definition prior to the comma.
For (2), assuming you know the name of the transaction_type, you can accomplish this by:
INSERT INTO transactions(type_id, amount)
VALUES ((SELECT id from transaction_types WHERE name = 'Withdrawal'), 999.99)
By the way, my PostgreSQL requires SERIAL instead of INTEGER AUTOINCREMENT

SQL Server trigger can't insert

I beginning to learn how to write trigger with this basic database.
I'm also making my very 1st database.
Schema
Team:
TeamID int PK (TeamID int IDENTITY(0,1) CONSTRAINT TeamID_PK PRIMARY KEY)
TeamName nvarchar(100)
History:
HistoryID int PK (HistoryID int IDENTITY(0,1) CONSTRAINT HistoryID_PK PRIMARY KEY)
TeamID int FK REF Team(TeamID)
WinCount int
LoseCount int
My trigger: when a new team is inserted, it should insert a new history row with that team id
CREATE TRIGGER after_insert_Player
ON Team
FOR INSERT
AS
BEGIN
INSERT INTO History (TeamID, WinCount, LoseCount)
SELECT DISTINCT i.TeamID
FROM Inserted i
LEFT JOIN History h ON h.TeamID = i.TeamID
AND h.WinCount = 0 AND h.LoseCount = 0
END
Executed it returns
The select list for the INSERT statement contains fewer items than the insert list. The number of SELECT values must match the number of INSERT columns.
Please help thank. I'm using SQL Server
The error text is the best guide, it is so clear ..
You try inserting one value from i.TeamID into three columns (TeamID,WinCount,LoseCount)
consider these WinCount and LoseCount while inserting.
Note: I Think the structure of History table need to revisit, you should select WinCount and LoseCount as Expressions not as actual columns.
When you specify insert columns, you say which columns you will be filling. But in your case, right after insert you select only one column (team id).
You either have to modify the insert to contain only one column, or select, to retrieve 3 fields as in insert.
If you mention the columns where values have to be inserted(Using INSERT-SELECT).
The SELECT Statement has to contain the same number of columns that have been specified to be inserted. Also, ensure they are of the same data type.(You might face some issues otherwise)

SQL Server If Not Exists insert in a recursive manner

I am new to SQL Server. Working with version 2014.
I have a table with GUID as the key. I have an insert statement
IF NOT EXISTS (select guid from table)
insert into table (,,) values (,,);
In this case, the insert will work if the guid does not exist; if it exists, I need to generate a new guid and perform the insertion. This does not stop with just two levels. I need to check for every guid that is generated and then insert accordingly. How do I do this with a query or, in the worst case, a stored procedure?
Alter the table make the GUID column auto generated. Then you don't have check for its existence every time during insertion.
CREATE TABLE Your_Table
(
Guid_ID UNIQUEIDENTIFIER DEFAULT NEWSEQUENTIALID() PRIMARY KEY,
Column_1 ...
)
If you cannot alter the table then
;with cte as
(
select newid(),value1,value2,..
)
Insert into Your_Table(Guid_ID,col1,col2,..)
Select newid(),value1,value2,..
from cte C
Where not exists (select 1 from Yourtable b where b.Guid_ID = c.Guid_ID )

Duplicating parent, child and grandchild records

I have a parent table that represents a document of-sorts, with each record in the table having n children records in a child table. Each child record can have n grandchild records. These records are in a published state. When the user wants to modify a published document, we need to clone the parent and all of its children and grandchildren.
The table structure looks like this:
Parent
CREATE TABLE [ql].[Quantlist] (
[QuantlistId] INT IDENTITY (1, 1) NOT NULL,
[StateId] INT NOT NULL,
[Title] VARCHAR (500) NOT NULL,
CONSTRAINT [PK_Quantlist] PRIMARY KEY CLUSTERED ([QuantlistId] ASC),
CONSTRAINT [FK_Quantlist_State] FOREIGN KEY ([StateId]) REFERENCES [ql].[State] ([StateId])
);
Child
CREATE TABLE [ql].[QuantlistAttribute]
(
[QuantlistAttributeId] INT IDENTITY (1, 1),
[QuantlistId] INT NOT NULL,
[Narrative] VARCHAR (500) NOT NULL,
CONSTRAINT [PK_QuantlistAttribute] PRIMARY KEY ([QuantlistAttributeId]),
CONSTRAINT [FK_QuantlistAttribute_QuantlistId] FOREIGN KEY ([QuantlistId]) REFERENCES [ql].[Quantlist]([QuantlistId]),
)
Grandchild
CREATE TABLE [ql].[AttributeReference]
(
[AttributeReferenceId] INT IDENTITY (1, 1),
[QuantlistAttributeId] INT NOT NULL,
[Reference] VARCHAR (250) NOT NULL,
CONSTRAINT [PK_QuantlistReference] PRIMARY KEY ([AttributeReferenceId]),
CONSTRAINT [FK_QuantlistReference_QuantlistAttribute] FOREIGN KEY ([QuantlistAttributeId]) REFERENCES [ql].[QuantlistAttribute]([QuantlistAttributeId]),
)
In my stored procedure, i pass in the QuantlistId I want to clone as #QuantlistId. Since the QuantlistAttribute table has a ForeignKey I can easily clone that as well.
INSERT INTO [ql].[Quantlist] (
[StateId],
[Title],
) SELECT
1,
Title,
FROM [ql].[Quantlist]
WHERE QuantlistId = #QuantlistId
SET #ClonedId = SCOPE_IDENTITY()
INSERT INTO ql.QuantlistAttribute(
QuantlistId
,Narrative)
SELECT
#ClonedId,
Narrative,
FROM ql.QuantlistAttribute
WHERE QuantlistId = #QuantlistId
The trouble comes down to the AttributeReference. If I cloned 30 QuantlistAttribute records, how do I clone the records in the reference table and match them up with the new records I just inserted in to the QuantlistAttribute table?
INSERT INTO ql.AttributeReference(
QuantlistAttributeId,
Reference,)
SELECT
QuantlistAttributeId,
Reference,
FROM ql.QuantlistReference
WHERE ??? I don't have a key to go off of for this.
I thought I could do this with some temporary linking tables that holds the old attribute id's along with the new attribute id's. I don't know how to go about inserting the old Attribute Id's in to a temp table along with their new ones. Inserting the existing Attributes, by QuantlistId, is easy enough, but I can't figure out how to make sure I link the correct new and old Id's together in some way, so that the AttributeReference table can be cloned right. If I could get the QuantlistAttribute new and old Id's linked, I could join on that temp table and figure out how to restore the relationship of the newly cloned references, to the newly cloned attributes.
Any help on this would be awesome. I've spent the last day and a half trying to figure this out with no luck :/
Please excuse some of the SQL inconsistencies. I re-wrote up the sql real quick, trimming out a lot of additional columns, related-tables and constraints that weren't needed for this question.
Edit
After doing a little digging around, I found that OUTPUT might be useful for this. Is there a way to use OUTPUT to map the QuantlistAttributeId records I just inserted, to the QuantlistAttributeId they originated from?
You can use OUTPUT to get the inserted rows.
You can insert the data into QuantlistAttribute based on the order of ORDER BY c.QuantlistAttributeId ASC
Have a temp table/table variable which 3 columns
an id identity column
new QuantlistAttributeId
old QuantlistAttributeId.
Use OUTPUT to insert new identity values of QuantlistAttribute into a temp table/table variable.
The new IDs are generated in the same order as c.QuantlistAttributeId
Use a row_number() ordered by QuantlistAttributeId to match the old QuantlistAttributeId and new QuantlistAttributeIds based on row_number() and id of the table variable and update the values or old QuantlistAttributeId in the table variable
Use the temp table and join with AttributeReference and insert records in one go.
Note:
ORDER BY during INSERT INTO SELECT and ROW_NUMBER() to get matching old QuantlistAttributeId is required because looking at your question, there seems to be no other logical key to map old and new records together.
Query for above Steps
DECLARE #ClonedId INT,#QuantlistId INT = 0
INSERT INTO [ql].[Quantlist] (
[StateId],
[Title]
) SELECT
1,
Title
FROM [ql].[Quantlist]
WHERE QuantlistId = #QuantlistId
SET #ClonedId = SCOPE_IDENTITY()
--Define a table variable to store the new QuantlistAttributeID and use it to map with the Old QuantlistAttributeID
DECLARE #temp TABLE(id int identity(1,1), newAttrID INT,oldAttrID INT)
INSERT INTO ql.QuantlistAttribute(
QuantlistId
,Narrative)
--New QuantlistAttributeId are created in the same order as old QuantlistAttributeId because of ORDER BY
OUTPUT inserted.QuantlistAttributeId,NULL INTO #temp
SELECT
#ClonedId,
Narrative
FROM ql.QuantlistAttribute c
WHERE QuantlistId = #QuantlistId
--This is required to keep new ids generated in the same order as old
ORDER BY c.QuantlistAttributeId ASC
;WITH CTE AS
(
SELECT c.QuantlistAttributeId,
--Use ROW_NUMBER to get matching id which is same as the one generated in #temp
ROW_NUMBER()OVER(ORDER BY c.QuantlistAttributeId ASC) id
FROM ql.QuantlistAttribute c
WHERE QuantlistId = #QuantlistId
)
--Update the old value in #temp
UPDATE T
SET oldAttrID = CTE.QuantlistAttributeId
FROM #temp T
INNER JOIN CTE ON T.id = CTE.id
INSERT INTO ql.AttributeReference(
QuantlistAttributeId,
Reference)
SELECT
T.NewAttrID,
Reference
FROM ql.AttributeReference R
--Use OldAttrID to join with ql.AttributeReference and insert NewAttrID
INNER JOIN #temp T
ON T.oldAttrID = R.QuantlistAttributeId
Hope this helps.

SQL Server Database unique number generation on any record insertion

I have like 11 columns in my database table and i am inserting data in 10 of them. i want to have a unique number like "1101 and so on" in the 11th column.
Any idea what should i do?? Thanks in advance.
SQL Server 2012 and above you can generate Sequence
Create SEQUENCE RandomSeq
start with 1001
increment by 1
Go
Insert into YourTable(Id,col1...)
Select NEXT VALUE FOR RandomSeq,col1....
or else you can use Identity
Identity(seed,increment)
You can start the seed from 1101 and increment the sequence by 1
Create table YourTable
(
id INT IDENTITY(1101,1),
Col varchar(10)
)
If you want to have that unique number in a different field then you can manipulate that field with primary key and insert that value.
If you want in primary key value, then open the table in design mode, go to 'Identity specification', set 'identity increment' and 'identity seed' as you want.
Alternatively you can use table script like,
CREATE TABLE Persons
(
ID int IDENTITY(12,1) PRIMARY KEY,
FName varchar(255) NOT NULL,
)
here the primary key will start seeding from 12 and seed value will be 1.
If you have your table definition already in place you can alter the column and add Computed column marked as persisted as:
ALTER TABLE tablename drop column column11;
ALTER TABLE tablename add column11 as '11'
+right('000000'+cast(ID as varchar(10)), 2) PERSISTED ;
--You can change the right operator value from 2 to any as per the requirements.
--Also replace ID with the identity column in your table.
create table inc
(
id int identity(1100,1),
somec char
)