CREATE TABLE [dbo].[Test]
( [GID] INT
, [ID] INT
, [Val] VARCHAR(10)
, [ParentId] INT
, CONSTRAINT [PK_Test] PRIMARY KEY ( [GID], [ID] )
, CONSTRAINT [FK_Test_ParentId] FOREIGN KEY ( [GID], [ParentId] ) REFERENCES [dbo].[Test] ( [GID], [id] ) );
INSERT INTO [dbo].[Test] ([GID], [ID], [Val], [ParentId])
SELECT 1, 1,'One',NULL
UNION
SELECT 1, 2,'Two',NULL
UNION
SELECT 1, 3,'Three',1
UNION
SELECT 1, 4,'Four',1
UNION
SELECT 2, 1,'One',NULL
UNION
SELECT 2, 2,'Two',1;
SELECT *
FROM [dbo].[Test];
/* Test Cases */
--UPDATE [dbo].[Test]
--SET [ParentId] = 2
--WHERE [GID] = 1 AND [ID] = 1; -- Should FAIL because this record is already marked as a Parent of another record(s) (i.e. [GID] = 1 AND [ID] IN (3, 4)
--INSERT INTO [dbo].[Test] ( [GID], [ID], [Val], [ParentId] )
--SELECT 1, 5, 'Five', 4; -- Should FAIL because [GID] = 1 AND [ID] = 4 already has a non-null [ParentId].
DROP TABLE [dbo].[Test];
Goal:
To create a check constraint (scalar function with BIT return where 1 = valid, 0 = invalid?) that prevents the mapped ParentID record from having a NOT-NULL ParentId or preventing an INSERT of a record with a ParentId that already has a NOT-NULL ParentID assigned to it.
I tried to play around with LEFT Joins/NULL check logic but not really getting what I'm looking for.
Related
I'm trying to insert data into multiple tables if it doesn't already exist. I can't seem to figure this out at all.
Table 1:
CREATE TABLE [dbo].[search_results]
(
[company_id] [int] NULL,
[title] [text] NULL,
[link] [text] NULL,
[domain] [text] NULL,
[index] [int] NULL,
[id] [int] PRIMARY KEY IDENTITY(1,1) NOT NULL
)
Table 2:
CREATE TABLE [dbo].[statements]
(
[statement_link_id] [int] NULL,
[statement_page] [text] NULL,
[statement_text_location] [text] NULL,
[statement_description] [text] NULL,
[statement_description_html] [text] NULL,
[statement] [int] NULL,
[id] [int] PRIMARY KEY IDENTITY(1,1) NOT NULL
)
This is what I want to do:
check to see if the company_id and the link already exist in the table or not.
SELECT *
FROM search_results
WHERE company_id = 4 AND link = 'https://test.com';
If the data does not exist, insert it into two tables
INSERT INTO search_results (company_id, link, title, domain)
VALUES (4, 'https://test.com', 'title', 'test.com');
and also insert the search_result last inserted id to the following table. corporate_statement value is always 1
INSERT INTO corporate_statements (statement_link_id, corporate_statement)
VALUES (743, 1);
I'm trying this based on what I found on SO
DECLARE #result AS TABLE (id int, company_id int, link text, title text, domain text);
WITH cte AS
(
SELECT *
FROM (VALUES (4, 'https://test.com', null, null)) AS t(company_id, link, title, domain)
)
INSERT INTO #result
SELECT *
FROM
(INSERT INTO dbo.search_results (company_id, link, title, domain)
OUTPUT inserted.*
SELECT * FROM cte
WHERE NOT EXISTS (SELECT * FROM dbo.[search_results]
WHERE company_id = cte.company_id
AND CAST(link AS varchar(250)) = CAST(cte.link AS varchar(50))
)) r
SELECT * FROM #result;
Even trying with a single insert statement, I get the following error:
Msg 213, Level 16, State 1, Line 8
Column name or number of supplied values does not match table definition.
As you can see, I also tried to cast it to varchar since it was throwing error when I hadn't. How can update this?
To me - this seems a lot cleaner, and it also will be a lot simpler to understand (and maintain!) in the future:
-- check to see if your data already exists
IF NOT EXISTS (SELECT *
FROM search_results
WHERE company_id = 4 AND link = 'https://test.com')
BEGIN TRY
BEGIN TRANSACTION
-- if not -> insert into the first table
INSERT INTO search_results (company_id, link, title, domain)
VALUES (4, 'https://test.com', 'title', 'test.com');
-- grab the last identity value from that previous INSERT
DECLARE #LastId INT;
SELECT #LastId = SCOPE_IDENTITY();
-- insert into the second table
INSERT INTO corporate_statements (statement_link_id, corporate_statement)
VALUES (#LastId, 1);
COMMIT;
END TRY
BEGIN CATCH
-- in case of an error rollback the full transaction
ROLLBACK;
END CATCH;
and you're done. Or am I missing something? I think this would be doing what you're described in the intro of your post - not necessarily what you're showing in your code...
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)
I have this query:
CREATE TABLE [factOffertDetail](
[idOffertRow] [INT] IDENTITY(1,1) NOT NULL,
[idOffertRegion] [INT] NOT NULL,
[idProduct] [INT] NOT NULL,
[Qty] [DECIMAL](12, 2) NULL,
[idUnitPrice] [TINYINT] NULL
)
DECLARE #TMP2 TABLE (
idOffertRowNEW INT,
idOffertRow INT
)
INSERT INTO factOffertDetail
( idOffertRegion ,
idProduct ,
Qty ,
idUnitPrice
)
OUTPUT inserted.idOffertRow INTO #TMP2(d.idOffertRowNEW)
SELECT
d.idOffertRegion,
d.idProduct ,
d.Qty ,
d.idUnitPrice
FROM factOffertDetail d
I need to get the keys of the old and the new idOffertRow generated by identity.
idOffertRow is the identity (1,1) key of the factOffertDetail table.
How can I do this with an insert ?
Is it possible or I have to switch to merge command ?
Thanks to support
I would recommend to doing this:
Alter your table with new coloum,
ALTER TABLE [factOffertDetail]
ADD [ParentId] [INT] NULL
then,
INSERT INTO factOffertDetail
( ParentId,
idOffertRegion ,
idProduct ,
Qty ,
idUnitPrice
)
OUTPUT inserted.idOffertRow,inserted.ParentId INTO #TMP2(idOffertRowNEW,idOffertRow)
SELECT
d.idOffertRow,
d.idOffertRegion,
d.idProduct ,
d.Qty ,
d.idUnitPrice
FROM factOffertDetail d
Thank You!
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
I am working with SQL sever table and at technical point I am stuck.
Below I am attaching a screen-shot of the table query and result also the required logic.
There are two portions of query, one is without any condition and second is with condition that select "qty" when parent_id is NULL else print 0,
I want to print the "qty" of sub-item when its qty differs from its parent's "qty"
Here is the script:
GO
CREATE TABLE [dbo].[#Temp_order](
[order_id] [int] IDENTITY(1,1) NOT NULL,
[orderdate] [datetime] NULL
) ON [PRIMARY]
GO
GO
CREATE TABLE [dbo].[#Temp_order_list](
[order_list_id] [int] IDENTITY(1,1) NOT NULL,
[order_id] [int] NOT NULL,
[qty] [int] NOT NULL,
[price] [money] NOT NULL,
[type] [int] NOT NULL,
[parent_id] [int] NULL,
CONSTRAINT [PK_Temp_order_list] PRIMARY KEY CLUSTERED
(
[order_list_id] 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
/*
*/
INSERT INTO #Temp_order
( orderdate )
VALUES ( '2015-01-16 05:08:53' -- orderdate - datetime
)
INSERT INTO #Temp_order_list
( order_id, qty, price, type, parent_id )
VALUES ( (SELECT MAX(order_id) FROM #Temp_order), -- order_id - int
1, -- qty - int
10, -- price - money
2, -- type - int
NULL -- parent_id - int
)
DECLARE #ParentID AS INTEGER
SELECT #ParentID = MAX(order_list_id) FROM #Temp_order_list
INSERT INTO #Temp_order_list
( order_id, qty, price, type, parent_id )
VALUES ( (SELECT MAX(order_id) FROM #Temp_order), -- order_id - int
1, -- qty - int
12, -- price - money
3, -- type - int
#ParentID -- parent_id - int
)
INSERT INTO #Temp_order_list
( order_id, qty, price, type, parent_id )
VALUES ( (SELECT MAX(order_id) FROM #Temp_order), -- order_id - int
4, -- qty - int
13, -- price - money
3, -- type - int
#ParentID -- parent_id - int
)
SELECT * FROM #Temp_order_list WHERE order_id = 1
SELECT #Temp_order.order_id ,#Temp_order_list.order_list_id,#Temp_order_list.price,#Temp_order_list.type,
CASE WHEN #Temp_order_list.parent_id IS NOT NULL THEN 0
ELSE
ISNULL(#Temp_order_list.qty ,'') END AS quantity
FROM #Temp_order
INNER JOIN #Temp_order_list ON #Temp_order.order_id = #Temp_order_list.order_id
WHERE #Temp_order.order_id = 1
DROP TABLE #Temp_order
DROP TABLE #Temp_order_list
Any better solution?
Looking at your last comment, I can suggest to add self join and check that condition :
SELECT ordr.order_id,
list.order_list_id,
list.price,
list.type,
CASE
WHEN parentlist.order_list_id IS NOT NULL THEN list.qty
WHEN list.parent_id IS NOT NULL THEN 0
ELSE ISNULL(list.qty, '')
END AS quantity
FROM #Temp_order ordr
INNER JOIN #Temp_order_list list
ON ordr.order_id = list.order_id
LEFT JOIN #Temp_order_list parentlist
ON parentlist.order_list_id = list.parent_id
AND list.qty > parentlist.qty
AND list.type = 3
WHERE ordr.order_id = 1