How to update different columns depending on differences between tables - sql

I have three tables, table 1, table 2 and table 3. Table 1 records all the existing records, and table 2 records the delta (new updates) to be applied to table 1.
Table 3 is the resultant table.
Table 1 and 3 structure: ID is the primary key
ID, date, location, age, count
Table 2 structure: ID is the primary key
ID, date, location, age, count, ChangeType
Table 2 records new update values only for fields that changed in table 1.
For example:
Table 1
1, 03/03/2017, A, 11, 1
2, 01/03/2017, B, 39, 1
3, 01/01/2017, D, 1, 1
Table 2
2, 03/03/2017,NULL, NULL,2, Update
1, NULL, CC, NULL, NULL, Update
Therefore table 3 should be
1, 03/03/2017, CC, 11, 1
2, 03/03/2017, B, 39, 2
3, 01/01/2017, D, 1, 1
Any suggestions would be appreciated.
GO
/****** Object: Table [dbo].[Table_1] Script Date: 03/03/2017 10:41:28 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Table_1](
[ID] [int] NOT NULL,
[date] [date] NULL,
[location] [nvarchar](50) NULL,
[age] [int] NULL,
[count] [int] NULL
) ON [PRIMARY]
GO
/****** Object: Table [dbo].[Table_2] Script Date: 03/03/2017 10:41:28 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Table_2](
[ID] [int] NOT NULL,
[date] [date] NULL,
[location] [nvarchar](50) NULL,
[age] [int] NULL,
[count] [int] NULL,
[ChangeTyppe] [nvarchar](10) NULL
) ON [PRIMARY]
GO
/****** Object: Table [dbo].[Table_3] Script Date: 03/03/2017 10:41:28 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Table_3](
[ID] [int] NOT NULL,
[date] [date] NULL,
[location] [nvarchar](50) NULL,
[age] [int] NULL,
[count] [int] NULL
) ON [PRIMARY]
GO
INSERT [dbo].[Table_1] ([ID], [date], [location], [age], [count]) VALUES (1, CAST(0x863C0B00 AS Date), N'A', 11, 1)
GO
INSERT [dbo].[Table_1] ([ID], [date], [location], [age], [count]) VALUES (2, CAST(0x843C0B00 AS Date), N'B', 39, 1)
GO
INSERT [dbo].[Table_1] ([ID], [date], [location], [age], [count]) VALUES (3, CAST(0x493C0B00 AS Date), N'D', 1, 1)
GO
INSERT [dbo].[Table_2] ([ID], [date], [location], [age], [count], [ChangeTyppe]) VALUES (2, CAST(0x863C0B00 AS Date), NULL, NULL, 2, N'Update')
GO
INSERT [dbo].[Table_2] ([ID], [date], [location], [age], [count], [ChangeTyppe]) VALUES (1, NULL, N'CC', NULL, NULL, N'Update')
GO

If all you need is a one time thing, then this should work.
Left Join the two tables on the primary key and take the value from T2 if it is not null. Take the value from T1 if the value from 2 was null.
Coalesce will return the first value which is not null.
The values from T2 will be null if the row did not exist in T2 or if the value in T2 was null - per ID.
INSERT dbo.Table_3
( ID, date, location, age, count )
SELECT t1.ID ,
[date] = COALESCE(t2.date, t1.date) ,
[location] = COALESCE(t2.location, t1.location) ,
[age] = COALESCE(t2.age, t1.age) ,
[count] = COALESCE(t2.count, t1.count)
FROM dbo.Table_1 t1
LEFT OUTER JOIN dbo.Table_2 t2 ON t2.ID = t1.ID

Related

SQL Server CTE Hierarchy query aggregation

I want to calculate SUM of all children with CTE here is DDL/DML. 0 values are which I don't know and to be calculated through aggregation
CREATE TABLE [dbo].[Product]
(
[ID] [INT] IDENTITY(1,1) NOT NULL,
[Hierarchy] [VARCHAR](100) NOT NULL,
[ParentID] [INT] NULL,
[SalesAmount] [INT] NULL
) ON [PRIMARY]
GO
SET IDENTITY_INSERT [dbo].[Product] ON
GO
INSERT [dbo].[Product] ([ID], [Hierarchy], [ParentID], [SalesAmount])
VALUES (1, N'root', NULL, 0),
(2, N'T1', 1, 0),
(3, N'T2', 1, 0),
(4, N'C1', 2, 0),
(5, N'C2', 3, 0),
(6, N'C3', 2, 0),
(7, N'P1', 4, 1000),
(8, N'P2', 5, 2000),
(9, N'P3', 6, 3000)
I tried below query and it gives me following output,
WITH CT AS
(
SELECT
ID, Hierarchy, ParentID, 0 AS Level,
CAST ([Hierarchy] AS VARCHAR (MAX)) AS [Linkeage]
FROM
dbo.Product
WHERE
ParentID IS NULL
UNION ALL
SELECT
pc.ID, pc.Hierarchy, pc.ParentID, p1.Level + 1,
p1.Linkeage + ' -> ' + CAST ([pc].[Hierarchy] AS VARCHAR (MAX))
FROM
dbo.Product AS pc
JOIN
CT AS p1 ON p1.ID = pc.ParentID
),
Aggr AS
(
SELECT
TC.ParentID,
SUM(T.SalesAmount) AS sum_TotalAmt
FROM
CT TC
INNER JOIN
Product AS T ON TC.ID = T.ID
GROUP BY
TC.ParentID
)
SELECT
ID, Hierarchy, T.ParentID, Level, Linkeage, A.sum_TotalAmt
FROM
CT AS T
LEFT JOIN
Aggr AS A ON ISNULL(T.Id, T.ParentID) = A.ParentID
I need existing output + underlined rows as well.
I figured out by my-self by in different approach, i wanted to get aggregates of multiple group by values,
CREATE TABLE [dbo].[Product](
[ProductID] [int] IDENTITY(1,1) NOT NULL,
[ProductType] [varchar](100) NOT NULL,
[ProductCategory] [varchar](100) NOT NULL,
[ProductName] [varchar](100) NOT NULL,
[SalesAmount] [decimal]
) ON [PRIMARY]
So i can simply get output with below
select [ProductType], [ProductCategory], SUM( [SalesAmount] ) as TotalSales
from Product
GROUP BY ROLLUP (ProductType,ProductCategory)

Trouble using stored procedure to insert query results into table

I'm trying to do some testing on some tables but I seem to keep running into an error.
I'm trying to run the following stored procedure:
INSERT INTO [Customer].[TableA_test] ([CustomerID], [VisitID], [TransactionId], [ArrivalDT], [DataA], [DataB], [DataC], [SnapDate])
SELECT
b.CustomerID,
b.VisitID,
b.TransactionID,
b.ArrivalDT,
b.DataA,
b.DataB,
b.DataC,
SnapDate = GETDATE()
FROM
[Customer].[TableA_test] a
LEFT JOIN
[Customer].[TableB] b ON a.VisitID = b.VisitID
AND a.TransactionId = b.TransactionID
WHERE
a.TransactionID IS NULL
The procedure is meant to take the results from the query and insert them into the TableA. Table A has the exact same columns and data types as TableB. When I try to execute the stored procedure (code provided above), I get the following error:
Msg 241, Level 16, State 1, Procedure InsertTo_TableA_test, Line 27
Conversion failed when converting date and/or time from character string.
All of my date columns are set to datetime data type: ArrivalDT and the SnapDate. TableA_testing and TableB have the exact same column names and datatypes.
Is there something I'm missing?
Here's the table info for [Customer].[TableA_test]:
CREATE TABLE [Customer].[TableA_test]
(
[TransactionID] [VARCHAR](254) NULL,
[VisitID] [VARCHAR](254) NULL,
[ArrivalDT] [DATETIME] NULL,
[CustomerID] [VARCHAR](254) NULL,
[DataA] [VARCHAR](50) NULL,
[DataB] [VARCHAR](50) NULL,
[DataC] [VARCHAR](50) NULL,
[SnapDate] [DATETIME] NULL
)
And for TableB:
CREATE TABLE [Customer].[TableB]
(
[TransactionID] [VARCHAR](254) NULL,
[VisitID] [VARCHAR](254) NULL,
[ArrivalDT] [DATETIME] NULL,
[CustomerID] [VARCHAR](254) NULL,
[DataA] [VARCHAR](50) NULL,
[DataB] [VARCHAR](50) NULL,
[DataC] [VARCHAR](50) NULL,
[SnapDate] [DATETIME] NULL
)
Line 27 of my stored procedure is:
INSERT INTO [Customer].[JTM_NY_SPARCS_VitalSigns_test] ([CustomerID],[VisitID], [TransactionID], [ArrivalDT], [DataA], [DataB], [DataC], [SnapDate])
Here's the full read-out of the stored procedure:
USE [Database_3]
GO
/****** Object: StoredProcedure [Customer].[InsertTo_TableA_test] Script Date: 4/12/2019 11:49:17 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [Customer].[InsertTo_TableA_test]
/*
CREATED: 04/11/2019
*/
AS
BEGIN
INSERT INTO [Customer].[TableA_test] ([CustomerID], [VisitID], [TransactionId], [ArrivalDT], [DataA], [DataB], [DataC], [SnapDate])
SELECT
b.CustomerID,
b.VisitID,
b.TransactionID,
b.ArrivalDT,
b.DataA,
b.DataB,
b.DataC,
SnapDate = GETDATE()
FROM
[Customer].[TableA_test] a
LEFT JOIN
[Customer].[TableB] b ON a.VisitID = b.VisitID
AND a.TransactionId = b.TransactionID
WHERE
a.TransactionID IS NULL
END
GO
Example of a row of results when running the query from the stored procedure:
100010 [VisitID]
20000281542 [TransactionID]
2014-07-09 15:44:42.000 [ArrivalDT]
0032011 [CustomerID]
147 [DataA]
71 [DataB]
69 [DataC]
2019-04-12 11:54:23.753 [SnapDate]
From what I have seen in your comments, you said you are trying to insert from TableA_test to TableB. If that is the case, then your query should be:
INSERT INTO [Customer].[TableB] ([CustomerID],[VisitID],[TransactionId],[ArrivalDT],[DataA],[DataB],[DataC],[SnapDate])
SELECT
a.CustomerID,
a.VisitID,
a.TranactionID,
a.ArrivalDT,
a.DataA,
a.DataB,
a.DataC,
SnapDate = GETDATE()
FROM [Customer].[TableA_test] a
LEFT JOIN [Customer].[TableB] b
ON a.VisitID = b.VisitID
AND a.TransactionId = b.TransactionID
WHERE b.TransactionID IS NULL

SQL Server - SQL - INSERT VALUE from SELECT Statement

Help would be much appreciated: I want to update values to an audit table (dbo.Audit) prior to updating the same data column.
I have a SELECT statement to retrieve the values (which is created using dynamic SQL) stored in table dbo.[RuleSet], column [SelectStatement].
Issue: I am not sure how to update the Audit table.
CREATE TABLE [dbo].[Audit]
(
[ID] [int] IDENTITY(1,1) NOT NULL,
[UpdateID] [int] NULL,
[TableName] [varchar](250) NULL,
[Orig] [varchar](250) NULL
)
CREATE TABLE [dbo].[RuleSet]
(
[UpdateID] [int] IDENTITY(1,1) NOT NULL,
[VID] [int] NULL,
[TableName] [varchar](250) NOT NULL,
[SetColumn] [varchar](250) NOT NULL,
[SetValue] [varchar](250) NOT NULL,
[WhereClause] [varchar](256) NULL,
[SelectStatement] [varchar](4000) NULL
)
INSERT [dbo].[RuleSet] ([UpdateID], [VID], [TableName], [SetColumn], [SetValue], [WhereClause], [SelectStatement])
VALUES (1, 1, N'TableA', N'ColumnA', N'10', N'ColumnA > 10', N'SELECT ColumnA FROM TableA WHERE ColumnA > 10')
INSERT [dbo].[RuleSet] ([UpdateID], [VID], [TableName], [SetColumn], [SetValue], [WhereClause], [SelectStatement])
VALUES (3, 2, N'TableB', N'ColumnB', N'20', N'ColumnB > 20', N'SELECT ColumnB FROM TableB WHERE ColumnB > 20')
GO
The logic of the code I am trying to achieve is:
INSERT INTO [dbo].[Audit]([UpdateID], [TableName], [Orig])
SELECT
[UpdateID], [TableName],
--Value returned from executing the SELECT statement in column[SelectStatement]
FROM
dbo.[RuleSet]
Thank you
You can use EXECUTE sp_executesql to execute [SelectStatement] and store the result in a temp table or a variable. Then use that as a sub query to insert into [dbo].[Audit].
You could make it a lot easier on yourself if you stored your query in [SelectStatement] like this.
N'SELECT ColumnB INTO #TempB FROM TableB WHERE ColumnB > 20'
Then you can just execute it using sp_executesql and select from TempB for the insert.
EXECUTE sp_executesql (SELECT [SelectStatement] FROM [dbo].[RuleSet] where [UpdateID] = ?);
INSERT INTO [dbo].[Audit ] ([UpdateID], [TableName], [Orig])
SELECT [UpdateID], [TableName], #TempB.*
FROM dbo.[RuleSet], #TempB
WHERE [UpdateID] = ?
Note, my example is just a general suggestion and may need tweaking to execute.

SQL Server where clause with null column

I have an Employee table and how it works is, when a new employee is added, the column [DOR] will be null and [Status] will be 1. When the employee is being relieved from the company, the [DOR] column value will be the date which he/she left the company and [Status] is set to 0.
I need to fetch the details of all the employees who were available in a given date. The employees with Status as 1 and those who are not yet relieved till that date have to be fetched.
But I am not able to do the same as when equating with DOR, its null value and not returning any of the rows.
If I give the input as 2015-02-10, it should fetch the two records and when I give 2015-02-15, it should fetch only first record.
CREATE TABLE [Employee]
(
[EmployeeId] [int] IDENTITY(1000,1) NOT NULL,
[Name] [varchar](50) NOT NULL,
[RoleId] [int] NOT NULL,
[Email] [varchar](50) NULL,
[Contact] [varchar](50) NULL,
[DOJ] [date] NOT NULL,
[DOR] [date] NULL,
[Status] [bit] NOT NULL,
[Salary] [decimal](18, 2) NULL
)
INSERT [dbo].[Employee] ([EmployeeId], [Name], [RoleId], [Email], [Contact], [DOJ], [DOR], [Status], [Salary])
VALUES (1001, N'Employee 1', 3, N'', N'', CAST(0x8D390B00 AS Date), NULL, 1, CAST(6000.00 AS Decimal(18, 2)))
INSERT [dbo].[Employee] ([EmployeeId], [Name], [RoleId], [Email], [Contact], [DOJ], [DOR], [Status], [Salary])
VALUES (1002, N'Employee 2', 7, N'', N'', CAST(0x8D390B00 AS Date), CAST(0x9A390B00 AS Date), 0, CAST(4000.00 AS Decimal(18, 2)))
You need to use IS NULL operator instead of = NULL in your condition, like this:
SELECT *
FROM Employee
WHERE DOJ <= '2015-02-15'
AND (DOR IS NULL OR DOR > '2015-02-15')
Something like this?
select
EmployeeId,
Name
from
Employee
where
DOJ <= #searchDate and
(DOR is null or DOR > #searchDate)
Try this:
SELECT * FROM Employee
WHERE #dateOfSearch BETWEEN DOJ and COALESCE(DOR, '2099-12-31')
What this query does, is it checks if the search date is between start date and end date. If end date is null then COALESCE function is used to take the very high value date.
Another variation of the previous answers :-)
SELECT * FROM Employee
WHERE #dateOfSearch BETWEEN DOJ and COALESCE(DOR, #dateOfSearch)

SQL Inner Join customers with orders

if I have a two tables (one of customers, with their information including address, name, emails etc) and another of orders (with order number, shipping date, customer name who ordered that item), how could I show the email of the customers who have less than 3 orders?
I know I have to use an inner join and some alias's, but i'm not sure how to proceed.
Thanks!
what I have so far:
SELECT customer.email
FROM customer as cust
INNER JOIN (select customer_id, sum(line_qty) AS total
from orders as o ON cust.customer_id = o.customer_id
where total = (SELECT total < 3
FROM (select customer_id, sum(line_qty) AS total
from orders as o ON cust.customer_id = o.customer_id
) as sub);
I have created the full example with SQL. Just run the query to create the database, tables, and the Stored Procedure "Get Customer Orders".
There are sample data in the two table of "Customers" and the table "Orders" the relation is "1 Customer to MANY Orders" so there is a Foreign key for the Customer inside table Orders, to identify which customer had did the order. So.
First Create the Data base, Run this query.
Create DataBase [Customer_OrdersDB]
Refresh the Server explorer, you will find a database with that name has created.
Then Run the Query to create Stored Procedure and Tables.
USE [Customer_OrdersDB]
GO
CREATE PROCEDURE [dbo].[GetCustomer_Mail]
AS
BEGIN
select Email as Customer_Mail
from Customers as cust inner join Orders as ord
on cust.CustomerId = ord.OrderCustomerId
group by(Email)
having COUNT(ord.OrderCustomerId) < 3
END
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Customers](
[CustomerId] [int] IDENTITY(1,1) NOT NULL,
[CustomerName] [nvarchar](50) NULL,
[Address] [nvarchar](50) NULL,
[Email] [nvarchar](50) NULL,
CONSTRAINT [PK_Customers] PRIMARY KEY CLUSTERED
(
[CustomerId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
/****** Object: Table [dbo].[Orders] Script Date: 12/6/2014 5:19:11 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Orders](
[OrderId] [int] IDENTITY(1,1) NOT NULL,
[OrderDate] [datetime] NULL,
[OrderNumber] [nvarchar](50) NULL,
[OrderCustomerId] [int] NULL,
CONSTRAINT [PK_Orders] PRIMARY KEY CLUSTERED
(
[OrderId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET IDENTITY_INSERT [dbo].[Customers] ON
INSERT [dbo].[Customers] ([CustomerId], [CustomerName], [Address], [Email]) VALUES (1, N'Ahmed', N'Cairo', N'Ahmed#Yahoo.Com')
INSERT [dbo].[Customers] ([CustomerId], [CustomerName], [Address], [Email]) VALUES (2, N'Ali', N'Paris', N'Ali#yahoo.com')
INSERT [dbo].[Customers] ([CustomerId], [CustomerName], [Address], [Email]) VALUES (3, N'Samir', N'UK', N'Samir#msn.com')
SET IDENTITY_INSERT [dbo].[Customers] OFF
SET IDENTITY_INSERT [dbo].[Orders] ON
INSERT [dbo].[Orders] ([OrderId], [OrderDate], [OrderNumber], [OrderCustomerId]) VALUES (1, CAST(0x0000A2A600000000 AS DateTime), N'1234', 1)
INSERT [dbo].[Orders] ([OrderId], [OrderDate], [OrderNumber], [OrderCustomerId]) VALUES (2, CAST(0x0000A2C700000000 AS DateTime), N'555', 1)
INSERT [dbo].[Orders] ([OrderId], [OrderDate], [OrderNumber], [OrderCustomerId]) VALUES (3, CAST(0x00009CF100000000 AS DateTime), N'56d66', 1)
INSERT [dbo].[Orders] ([OrderId], [OrderDate], [OrderNumber], [OrderCustomerId]) VALUES (4, CAST(0x00009E9B00000000 AS DateTime), N'555we', 2)
INSERT [dbo].[Orders] ([OrderId], [OrderDate], [OrderNumber], [OrderCustomerId]) VALUES (5, CAST(0x0000A2A600000000 AS DateTime), N'1234', 1)
INSERT [dbo].[Orders] ([OrderId], [OrderDate], [OrderNumber], [OrderCustomerId]) VALUES (6, CAST(0x0000A2C700000000 AS DateTime), N'555', 1)
SET IDENTITY_INSERT [dbo].[Orders] OFF
ALTER TABLE [dbo].[Orders] WITH CHECK ADD CONSTRAINT [FK_Orders_Customers] FOREIGN KEY([OrderCustomerId])
REFERENCES [dbo].[Customers] ([CustomerId])
GO
ALTER TABLE [dbo].[Orders] CHECK CONSTRAINT [FK_Orders_Customers]
GO
Then to access your Stored procedure that you want to get the Customer Email if he/she did orders less than 3 Orders.
Go to Server/Object explorer in SQL server.
Select your data base of name [Customer_OrdersDB].
Select "Programbility".
Select "StoredProcedures".
Right Click on your storedprocedure "GetCustomer_Mail" and then select Execute.
Try this:
SELECT c.email
FROM customer AS c
LEFT OUTER JOIN orders AS o ON c.customer_id = o.customer_id
GROUP BY c.email
HAVING SUM(o.line_qty) < 3