Update a table and insert missing records - sql

I have a table with a foreign key column with some NULL records. I can select the records with missing column such as:
SELECT * FROM Outgoing WHERE Receipt_Id IS NULL
Now for each of these records I want to insert a new record in the table Receipts, get the inserted record's Id and set it as the value for Receipt_Id in this record.
Is this possible in a query?

It seems you are looking for inserted table
INSERT INTO Receipts (col1, col2....)
OUTPUT INSERTED.*
INTO #CreatedIds -- TEMP TABLE WHICH HOLDS RECENTLY INERTED DATA INCLUDING Receipt_Id (pk)
SELECT col1, col2....
FROM Outgoing
WHERE Receipt_Id IS NULL
To, see recently inserted records
SELECT c.*
FROM #CreatedIds c -- Note this is a table variable that you need to manual create.

Update: Since you are using Receipt table only as a sequence table. You should follow the updated approach which uses Sequences
Updated Answer:
All you need to do is to create a sequence say Receipts instead of a table with one column. And then update the Outgoing table with sequence numbers.
--create table Outgoing ( id int Primary Key IDENTITY(1,1),data nvarchar(100), record_id int);
--insert into Outgoing values ('john',NULL),('jane',NULL),('jean',NULL);
create sequence dbo.receipts as int start with 1 increment by 1;
update Outgoing
set record_id= NEXT VALUE FOR dbo.receipts
where record_id is null
select * from Outgoing
See working demo
Old Answer below
If you have ID column in both tables you can update Receipt_Id based on this column back into the Outgoing table
So you steps are :
1. insert records
DECLARE #LastRID bigint
SELECT #LastRID= MAX(Id) FROM Receipts
INSERT INTO Receipts(<col list>)
SELECT <col list> FROM Outgoing WHERE Receipt_Id IS NULL
update records based on uniqueness of all columns inserted from Outgoing to receipts using CHECKSUM function
update O
set O.Receipt_Id=R.Id
From Outgoing O
Join Receipts R
on CHECKSUM(o.<col list>)=CHECKSUM(R.<col list>)
and R.Id>#LastRID

Related

Create a record in table A and assign its id to table B

I have a set of companies and for each of them, I need to generate a UUID in another table.
companies table
detail_id (currently NULL for all companies)
details table
id
uuid
date
...
I'd like to update all companies with newly created detail like this:
UPDATE companies
SET details_id =
(
INSERT INTO details
(uuid, date)
VALUES (uuid_generate_v1(), now()::date)
RETURNING id
)
But that gives me a syntax error since I can't use INSERT INTO inside UPDATE.
What is a proper way to create a row in the details table and immediately set the newly created id in the companies table?
(I am using Postgres)
You can use a data-modifying CTE:
with new_rows as (
INSERT INTO details ("uuid", "date")
VALUES (uuid_generate_v1(), current_date)
RETURNING id
)
update companies
set details_id = new_rows.id
from new_rows

Creating a trigger that replaces null values in an insert with values already present in the table in SQL Server

I have a table, known as Fruit_Veg_Product_Table which is used to contain the characteristics of certain fruit and vegetable stock.
The table has the following columns:
Product_ID
Product_Type
Product_Name
Product_Colour
Product_Price
Product_In_Sale
Product_Stock_Level
Product_Height
Product_Width
Product_Depth
Product_Package_Height
Product_Package_Width
Product_Package_Depth
When a new product is inserted into the table, sometimes the product is inserted without any dimensions (the columns from Product_Height all the way to Product_Package_Depth). In this circumstance, the dimensions are entered as NULL.
I am in need of a SQL Server trigger that will replace all the NULL values from the attempted insert with the values corresponding to products that are already stored in the table which share a common Product_Type with the product that is being entered.
Any help with this problem is greatly appreciated.
Triggers have an INSERTED logical table that can be used to join the inserted row data back to the physical table. Here is an example:
CREATE TRIGGER Fruit_Veg_Product_Table_Trg
ON dbo.Fruit_Veg_Product_Table
FOR INSERT
AS
UPDATE dbo.Fruit_Veg_Product_Table
SET Product_Package_Height = ca.Product_Package_Height,
Product_Package_Width = ca.Product_Package_Width,
Product_Package_Depth = ca.Product_Package_Depth
FROM dbo.Fruit_Veg_Product_Table
CROSS APPLY
(
SELECT TOP 1
Product_Package_Height,
Product_Package_Width,
Product_Package_Depth
FROM dbo.Fruit_Veg_Product_Table AS fvpt
WHERE dbo.Fruit_Veg_Product_Table.Product_Type = fvpt.Product_Type
AND Product_Package_Height IS NOT NULL
AND Product_Package_Width IS NOT NULL
AND Product_Package_Depth IS NOT NULL
) AS ca
WHERE EXISTS
(
SELECT *
FROM INSERTED
WHERE INSERTED.Product_ID = dbo.Fruit_Veg_Product_Table.Product_ID
AND INSERTED.Product_Package_Height IS NULL
AND INSERTED.Product_Package_Width IS NULL
AND INSERTED.Product_Package_Depth IS NULL
);
GO

How to avoid cross join

I'm working on query which gives me history of records in db2 using
"FOR SYSTEM_TIME FROM '0001-01-01-00.00.00.000000' TO '9999-12-30-00.00.00.000000000000'".
Steps performed :
1) Added a record in 'NAME_TABLE' which contains 'SAMPLE_NAME' column.
2) Set the pk of the 'NAME_TABLE' as foreign key(NAME_FK) in another table called 'PREF_TABLE'.
3) Now, deleted that name from 'NAME_TABLE'. This results in deleting records from both the tables.
The problem I'm facing is that I'm getting cross join result.
Please help me to avoid cross joining.
Below are the transaction times for two actions performed.(insert and delete)
NAME_TABLE PREF_TABLE
15-Oct-2019 01:24:07 15-Oct-2019 01:24:17
15-Oct-2019 01:24:34 15-Oct-2019 01:24:17
15-Oct-2019 01:24:07 15-Oct-2019 01:24:34
15-Oct-2019 01:24:34 15-Oct-2019 01:24:34
Inserted into NAME_TABLE at 15-Oct-2019 01:24:07
Inserted into PREF_TABLE at 15-Oct-2019 01:24:17
deleted from both the tables at 15-Oct-2019 01:24:34
SELECT SAMPLE_NAME
FROM PREF_TABLE FOR SYSTEM_TIME FROM '0001-01-01-00.00.00.000000' TO
'9999-12-30-00.00.00.000000000000' PREN
INNER JOIN NAME_TABLE FOR SYSTEM_TIME FROM '0001-01-01-00.00.00.000000' TO
'9999-12-30-00.00.00.000000000000' PN ON PN.PK = PREN.NAME_FK
I expect the output of only two records i.e., for inserting and deleting.
But I'm getting 4 records instead.
CREATE TABLE NAME_TABLE
(
PK INT NOT NULL PRIMARY KEY,
SAMPLE_NAME INT,
sys_start TIMESTAMP(12) NOT NULL GENERATED ALWAYS AS ROW BEGIN,
sys_end TIMESTAMP(12) NOT NULL GENERATED ALWAYS AS ROW END,
ts_id TIMESTAMP(12) NOT NULL GENERATED ALWAYS AS TRANSACTION START ID,
PERIOD SYSTEM_TIME (sys_start, sys_end)
) IN USERSPACE1;
CREATE TABLE NAME_TABLE_HIST LIKE NAME_TABLE IN USERSPACE1;
ALTER TABLE NAME_TABLE ADD VERSIONING USE HISTORY TABLE NAME_TABLE_HIST;
CREATE TABLE PREF_TABLE
(
FK INT NOT NULL,
SAMPLE_NAME INT,
sys_start TIMESTAMP(12) NOT NULL GENERATED ALWAYS AS ROW BEGIN,
sys_end TIMESTAMP(12) NOT NULL GENERATED ALWAYS AS ROW END,
ts_id TIMESTAMP(12) NOT NULL GENERATED ALWAYS AS TRANSACTION START ID,
PERIOD SYSTEM_TIME (sys_start, sys_end),
CONSTRAINT PREF_TABLE_FK FOREIGN KEY (FK) REFERENCES NAME_TABLE (PK) ON DELETE CASCADE
) IN USERSPACE1;
CREATE TABLE PREF_TABLE_HIST LIKE PREF_TABLE IN USERSPACE1;
ALTER TABLE PREF_TABLE ADD VERSIONING USE HISTORY TABLE PREF_TABLE_HIST;
INSERT INTO NAME_TABLE (PK, SAMPLE_NAME) VALUES (1, 1);
INSERT INTO PREF_TABLE (FK, SAMPLE_NAME) VALUES (1, 1);
-- No rows in both tables
SELECT * FROM NAME_TABLE_HIST;
SELECT * FROM PREF_TABLE_HIST;
DELETE FROM NAME_TABLE;
-- One row in both tables
SELECT * FROM NAME_TABLE_HIST;
SELECT * FROM PREF_TABLE_HIST;
-- SELECT statement returns 1 row
SELECT PN.SAMPLE_NAME
FROM PREF_TABLE
FOR SYSTEM_TIME FROM '0001-01-01-00.00.00.000000' TO '9999-12-30-00.00.00.000000000000'
PREN
JOIN NAME_TABLE
FOR SYSTEM_TIME FROM '0001-01-01-00.00.00.000000' TO '9999-12-30-00.00.00.000000000000'
PN ON PN.PK = PREN.FK;
When you insert into a system temporal table, no rows inserted into the history table.
There are no duplicates so far.
You may have them, of course, if you insert / update the rows with the same ID in addition, but you should change the description of your sequence of steps to reproduce the problem and describe the desired result.
If you want to avoid duplicates, you may want to use
FOR SYSTEM_TIME AS OF 'timestamp_constant' (a "snapshot" of table contents at this time)
instead of
FOR SYSTEM_TIME FROM 'timestamp_constant1' TO 'timestamp_constant2'.
If you use the latter, I believe you should understand, that if you get more that one version of the same row, then it's expected to have such duplicates in the result set.

Update tables in one database from multiple tables in another database regularly

I have 2 databases in SQL Server, DB1 has multiple tables and some of the tables are updated with new records continuously. DB2 has only 1 table which should contain all the combined info from the multiple tables in DB1, and needs to be updated every 2 hours.
For example, DB1 has 3 tables: "ProductInfo", "StationRecord", "StationInfo". The first 2 tables both have a timestamp column that indicates when a record is created (i.e. the two tables are updated asynchronously, ONLY when a product passes all stations in "StationRecord" will "ProductInfo" be updated with a new product), and the last table is fixed.
The tables are as follows:
USE DB1
GO
CREATE TABLE ProductInfo
ProductID bigint Primary Key NOT NULL
TimeCreated datetime
ProductName nvarchar(255)
CREATE TABLE StationRecord
RecordID bigint Primary Key NOT NULL
TimeCreated datetime
ProductID bigint NOT NULL
StationID bigint
CREATE TABLE StationInfo
StationID bigint Primary Key NOT NULL
BOM_used nvarchar(255)
DB2 has only 1 table which contains a composite PK of "ProductID" & "StationID", as follows:
CREATE TABLE DB2.BOMHistory AS
SELECT
DB1.ProductInfo.ProductID
DB1.ProductInfo.TimeCreated AS ProductCreated
DB1.StationInfo.StationID
DB1.StationInfo.BOM_used
FROM DB1.ProductInfo
JOIN DB1.StationRecord
ON DB1.ProductInfo.ProductID = DB1.StationRecord.ProductID
JOIN DB1.StationInfo
ON DB1.StationRecord.StationID = DB1.StationInfo.StationID
constraint PK_BOMHistory Primary Key (ProductID,StationID)
I figured out the timing portion which is to use create a job with some pre-set schedules, and the job is to execute a stored procedure. The problem is how to write the stored procedure properly, which has to do the following things:
wait for the last product to pass all stations (and the "stationInfo" table is updated fully)
find all NEW records generated in this cycle in the tables in DB1
combine the information of the 3 tables in DB1
insert the combined info into DB2.BOMHistory
Here's my code:
ALTER Procedure BOMHistory_Proc
BEGIN
SELECT
DB1.ProductInfo.ProductID,
DB1.ProductInfo.TimeCreated AS ProductCreated
DB1.StationInfo.StationID,
DB1.StationInfo.BOM_used
into #temp_BOMList
FROM DB1.ProductInfo
JOIN DB1.StationRecord
ON DB1.ProductInfo.ProductID = DB1.StationRecord.ProductID
JOIN DB1.StationInfo
ON DB1.StationRecord.StationID = DB1.StationInfo.StationID
ORDER BY ProductInfo.ProductID
END
SELECT * from #temp_BOMList
INSERT INTO DB2.BOMHistory(ProductID, ProductCreated, StationID, BOM_used)
SELECT DISTINCT (ProductID, stationID)
FROM #temp_BOMList
WHERE (ProductID, stationID) NOT IN (SELECT ProductID, stationID FROM DB2.BOMHistory)
The Condition in the INSERT statement is not working, please provide some advice.
Also, should I use a table variable or a temp table for this application?
Try:
INSERT INTO DB2.BOMHistory(ProductID, ProductCreated, StationID, BOM_used)
SELECT DISTINCT tb.ProductID, tb.ProductCreated, tb.StationID, tb.BOM_used
FROM #temp_BOMList tb
WHERE NOT EXISTS
(SELECT * FROM DB2.BOMHistory WHERE ProductID = tb.ProductID AND StationID = tb.StationID)

Inserting a Row in a Table from Select Query

I'm using two Stored Procedures and two Table in My Sql Server.
First Table Structure.
Second Table Structure.
When a Customer books a Order then the Data will be Inserted in Table 1.
I'm using a Select Query in another Page Which Selects the Details from the Second Table.
If a row with a billno from first table is not Present in Second Table I want to Insert into the Second Table with some Default Values in the Select Query. How can I do this
??
If you want to insert in the same query, you will have to create a stored procedure. There you'll query if row exists in second table, and, if not, insert a new entity in second table.
Your code should look something like this:
-- --------------------------------------------------------------------------------
-- Routine DDL
-- Note: comments before and after the routine body will not be stored by the server
-- --------------------------------------------------------------------------------
DELIMITER $$
CREATE DEFINER=`table`#`%` PROCEDURE `insertBill`(IN billNo int, val1 int, val2 int, val3 int)
BEGIN
DECLARE totalres INT DEFAULT 0;
select count(*) from SECOND_TABLE where Bill_Number = billNo INTO totalres;
IF totalres < 1 THEN
INSERT into SECOND_TABLE values(val1,val2,val3);
END IF;
END
Val1,val2 and val3 are the valuest to be inserted into second table.
Hope this helps.
What you do is to LEFT JOIN the two tables and then select only the ones where the second table had no row to join, meaning the bill number were missing.
In the example below, you can replace #default_inform_status and #default_response_status with your default values.
INSERT INTO second_table (Bill_Number, Rest_Inform_Status, Rest_Response_Status)
SELECT ft.Bill_Number, #default_inform_status, #default_response_status
FROM first_table ft
LEFT JOIN second_table st
ON st.Bill_Number = ft.Bill_number
WHERE st.Bill_Number IS NULL
If it is possible to have duplicates of the same Bill_Number in the first table, you should also add a DISTINCT after the SELECT. But considering the fact that it is a primary key, this is no issue for you.