SQL command not properly ended with insert statement - database

hen I try to insert multiple rows of values, I write exactly the statement below, but get an error that "SQL command not properly ended". I cannot see where the error comes from, could anyone help me with this?
INSERT INTO employees
VALUES
(100, 'Patel', 'Ralph', 22333, 'rpatel#mail.com',1, NULL, 'Sales Rep'),
(101, 'Denis', 'Betty', 33444, 'bdenis#mail.com', 4, NULL, 'Sales Rep'),
(102, 'Biri', 'Ben', 44555, 'bbrir#mail.com', 2, NULL, 'Sales Rep'),
(103, 'Newman', 'Chad', 66777, 'cnewman#mail.com', 3, NULL, 'Sales Rep'),
(104, 'Ropeburn', 'Andrey', 77888, 'aropeburn#mail.com', 1, NULL, 'Sales Rep');

Your code will work in sql server and mysql. For oracle:
INSERT INTO employees
WITH emp AS (
SELECT 100, 'Patel', 'Ralph', 22333, 'rpatel#mail.com',1, NULL, 'Sales Rep' FROM dual UNION ALL
SELECT 101, 'Denis', 'Betty', 33444, 'bdenis#mail.com', 4, NULL, 'Sales Rep' FROM dual UNION ALL
SELECT 102,'Biri', 'Ben', 44555, 'bbrir#mail.com', 2, NULL, 'Sales Rep' FROM dual UNION ALL
SELECT 103,'Newman', 'Chad', 66777, 'cnewman#mail.com', 3, NULL, 'Sales Rep' FROM dual union all
select 104, 'Ropeburn', 'Andrey', 77888, 'aropeburn#mail.com', 1, NULL, 'Sales Rep'from dual
) select * from emp;

If DBMS == OracleDB then it does not support more than one data block in INSERT .. VALUES. Use INSERT .. SELECT instead:
INSERT INTO employees
SELECT 100, 'Patel', 'Ralph', 22333, 'rpatel#mail.com',1, NULL, 'Sales Rep' FROM DUAL UNION ALL
SELECT 101, 'Denis', 'Betty', 33444, 'bdenis#mail.com', 4, NULL, 'Sales Rep' FROM DUAL UNION ALL
SELECT 102, 'Biri', 'Ben', 44555, 'bbrir#mail.com', 2, NULL, 'Sales Rep' FROM DUAL UNION ALL
SELECT 103, 'Newman', 'Chad', 66777, 'cnewman#mail.com', 3, NULL, 'Sales Rep' FROM DUAL UNION ALL
SELECT 104, 'Ropeburn', 'Andrey', 77888, 'aropeburn#mail.com', 1, NULL, 'Sales Rep' FROM DUAL;
fiddle
Alternatively you may use 5 separate queries:
INSERT INTO employees VALUES (100, 'Patel', 'Ralph', 22333, 'rpatel#mail.com',1, NULL, 'Sales Rep');
INSERT INTO employees VALUES (101, 'Denis', 'Betty', 33444, 'bdenis#mail.com', 4, NULL, 'Sales Rep');
INSERT INTO employees VALUES (102, 'Biri', 'Ben', 44555, 'bbrir#mail.com', 2, NULL, 'Sales Rep');
INSERT INTO employees VALUES (103, 'Newman', 'Chad', 66777, 'cnewman#mail.com', 3, NULL, 'Sales Rep');
INSERT INTO employees VALUES (104, 'Ropeburn', 'Andrey', 77888, 'aropeburn#mail.com', 1, NULL, 'Sales Rep');

Related

SQL Server : select where following (sequence) rows with the same column value as current column equal to parameters

Script:
IF OBJECT_ID('tempdb..#Table2') IS NOT NULL DROP TABLE #Table;
CREATE TABLE #GPIO ([NUM] TINYINT, [MaterialIntID] BIGINT, [ElementIntID] BIGINT, [DateAdded] DATETIME);
INSERT INTO #GPIO VALUES (4, 8, NULL, '2019-01-06 00:01:14.190');
INSERT INTO #GPIO VALUES (4, 8, NULL, '2019-01-06 00:01:26.023');
INSERT INTO #GPIO VALUES (6, 9, 11, '2019-01-06 03:29:07.840');
INSERT INTO #GPIO VALUES (4, 8, NULL, '2019-01-06 03:40:33.300');
INSERT INTO #GPIO VALUES (4, 9, 11, '2019-01-06 03:40:33.300');
INSERT INTO #GPIO VALUES (5, 8, NULL, '2019-01-06 03:50:18.490');
INSERT INTO #GPIO VALUES (5, 9, 17, '2019-01-06 03:50:18.490');
INSERT INTO #GPIO VALUES (5, 8, NULL, '2019-01-06 03:52:33.303');
INSERT INTO #GPIO VALUES (5, 9, 5, '2019-01-06 03:52:33.303');
INSERT INTO #GPIO VALUES (4, 8, NULL, '2019-01-06 03:55:28.417');
INSERT INTO #GPIO VALUES (4, 9, 10, '2019-01-06 03:55:28.417');
INSERT INTO #GPIO VALUES (4, 9, 7, '2019-01-06 03:56:35.370');
INSERT INTO #GPIO VALUES (4, 9, 2, '2019-01-06 03:57:36.370');
INSERT INTO #GPIO VALUES (5, 9, 5,'2019-01-06 04:01:15.127');
INSERT INTO #GPIO VALUES (5, 9, 7, '2019-01-06 03:58:35.370');
INSERT INTO #GPIO VALUES (5, 9, 7,'2019-01-06 04:01:16.127');
INSERT INTO #GPIO VALUES (5, 8, 7,'2019-01-06 04:01:17.127');
INSERT INTO #GPIO VALUES (5, 9, 7,'2019-01-06 04:01:18.127');
INSERT INTO #GPIO VALUES (4, 9, 7, '2019-01-06 04:01:00.370');
And I have these declarations:
CASE 1
#ActionDate DATE = '2019-01-07',
#MaterialIntID BIGINT = NULL,
#ElementIntID BIGINT = NULL,
#SameNum BIT = 0,
#Counti INT = 2;
Results 1
CASE 2
#ActionDate DATE = '2019-01-07',
#MaterialIntID BIGINT = NULL,
#ElementIntID BIGINT = NULL,
#SameNum BIT = 0,
#Counti INT = 3;
Results 2
CASE 3
#ActionDate DATE = '2019-01-07',
#MaterialIntID BIGINT = 9,
#ElementIntID BIGINT = NULL,
#SameNum BIT = 0,
#Counti INT = 2;
Results 3
CASE 4
#ActionDate DATE = '2019-01-07',
#MaterialIntID BIGINT = 9,
#ElementIntID BIGINT = 7,
#SameNum BIT = 0,
#Counti INT = 2;
Results 4
CASE 5
#ActionDate DATE = '2019-01-07',
#MaterialIntID BIGINT = 9,
#ElementIntID BIGINT = 7,
#SameNum BIT = 1,
#Counti INT = 2;
Results 5
CASE 6
#ActionDate DATE = '2019-01-07',
#MaterialIntID BIGINT = 9,
#ElementIntID BIGINT = NULL,
#SameNum BIT = 1,
#Counti INT = 2;
Results 6
CASE 7
#ActionDate DATE = '2019-01-07',
#MaterialIntID BIGINT = NULL,
#ElementIntID BIGINT = NULL,
#SameNum BIT = 1,
#Counti INT = 3;
Results 7
I did this script but it only PARTITION by [MaterialIntID]. I need to consider also PARTITION by [ElementIntID] but only if i have parameter named #ElementIntID in the declaration and also PARTITION by [NUM] but only if i have parameter
the count must be at least equal to #Counti
;WITH [FirstList] AS
(
SELECT [NUM], [DateAdded], [MaterialIntID], [ElementIntID],
ROW_NUMBER() OVER (ORDER BY [DateAdded]) -
ROW_NUMBER() OVER (PARTITION BY [MaterialIntID] ORDER BY [DateAdded]) AS [GRP]
FROM [Gpio]
WHERE DATEDIFF(DAY, [DateAdded], #ActionDate)=1
)
SELECT [TT].[NUM], [TT].[MaterialIntID], [TT].[ElementIntID], [TT].[DateAdded], [TT].[GRP]
FROM [FirstList] AS [TT]
JOIN ( SELECT [MaterialIntID], [GRP]
FROM [FirstList]
GROUP BY [MaterialIntID], [GRP]
HAVING COUNT(*) >= #Counti) AS [HV] ON [TT].[MaterialIntID]=[HV].[MaterialIntID] AND [TT].[GRP]=[HV].[GRP]

Eliminate row in XML based on criteria

here's the script to create the needed data:
CREATE TABLE [dbo].[TestXML](
[ID] [int] NOT NULL,
[PID] [int] NULL,
[Code] [int] NULL,
[Col1] [int] NULL,
[Col2] [int] NULL,
[Col3] [decimal](6, 2) NULL,
[Col4] [decimal](6, 2) NULL,
[Col5] [int] NULL,
CONSTRAINT [PK_TestXML] PRIMARY KEY CLUSTERED ([ID] ASC)
)
GO
CREATE TABLE [dbo].[XML_Columns_Reference](
[TableName] nvarchar(10) NULL,
[TableNameXML] nvarchar(10) NULL,
[ColumnName] nvarchar(10) NULL,
[ColumnNameXML] nvarchar(10) NULL,
[ColumnOrder] [int] NULL,
[GroupName] nvarchar(10) NULL,
[GroupOrder] [int] NULL,
[Category] [int] NULL
) ON [PRIMARY]
CREATE TABLE [dbo].[XML_NoUseCols_Ref](
[TableNameXML] nvarchar(10) NULL,
[Code] [int] NULL,
[ColumnName] nvarchar(10) NULL
) ON [PRIMARY]
GO
INSERT [dbo].[TestXML] ([ID], [PID], [Code], [Col1], [Col2], [Col3], [Col4], [Col5]) VALUES (1, 1000, 10, 1, 2, CAST(0.20 AS Decimal(6, 2)), CAST(0.10 AS Decimal(6, 2)), 1)
INSERT [dbo].[TestXML] ([ID], [PID], [Code], [Col1], [Col2], [Col3], [Col4], [Col5]) VALUES (2, 1000, 20, NULL, 1, CAST(1.00 AS Decimal(6, 2)), CAST(1.00 AS Decimal(6, 2)), 1)
INSERT [dbo].[TestXML] ([ID], [PID], [Code], [Col1], [Col2], [Col3], [Col4], [Col5]) VALUES (3, 1000, 30, NULL, NULL, CAST(2.00 AS Decimal(6, 2)), CAST(2.00 AS Decimal(6, 2)), 5)
INSERT [dbo].[XML_Columns_Reference] ([TableName], [TableNameXML], [ColumnName], [ColumnNameXML], [ColumnOrder], [GroupName], [GroupOrder], [Category]) VALUES (N'TestXML', N'T', N'Col1', N'N', 1, N'A', 2, NULL)
INSERT [dbo].[XML_Columns_Reference] ([TableName], [TableNameXML], [ColumnName], [ColumnNameXML], [ColumnOrder], [GroupName], [GroupOrder], [Category]) VALUES (N'TestXML', N'T', N'Col2', N'V', 2, N'A', 2, NULL)
INSERT [dbo].[XML_Columns_Reference] ([TableName], [TableNameXML], [ColumnName], [ColumnNameXML], [ColumnOrder], [GroupName], [GroupOrder], [Category]) VALUES (N'TestXML', N'T', N'Col3', N'N', 1, N'B', 3, NULL)
INSERT [dbo].[XML_Columns_Reference] ([TableName], [TableNameXML], [ColumnName], [ColumnNameXML], [ColumnOrder], [GroupName], [GroupOrder], [Category]) VALUES (N'TestXML', N'T', N'Col4', N'V', 2, N'B', 3, NULL)
INSERT [dbo].[XML_Columns_Reference] ([TableName], [TableNameXML], [ColumnName], [ColumnNameXML], [ColumnOrder], [GroupName], [GroupOrder], [Category]) VALUES (N'TestXML', N'T', N'Col5', N'A', 1, N'C', 1, NULL)
INSERT [dbo].[XML_NoUseCols_Ref] ([TableNameXML], [Code], [ColumnName]) VALUES (N'T', 20, N'Col1')
INSERT [dbo].[XML_NoUseCols_Ref] ([TableNameXML], [Code], [ColumnName]) VALUES (N'T', 30, N'Col1')
INSERT [dbo].[XML_NoUseCols_Ref] ([TableNameXML], [Code], [ColumnName]) VALUES (N'T', 30, N'Col2')
Here's the query I run:
DECLARE #PID int
SET #PID=1000
SELECT
GroupName as [#n],
(SELECT
Code [#n],
(SELECT
ColumnNameXML as [col/#n],
CASE name
WHEN 'Col1' THEN ISNULL(Col1,0)
WHEN 'Col2' THEN ISNULL(Col2,0)
WHEN 'Col3' THEN ISNULL(Col3,0)
WHEN 'Col4' THEN ISNULL(Col4,0)
WHEN 'Col5' THEN ISNULL(Col5,0)
END AS [col/col_value]
FROM sys.columns
CROSS JOIN TestXML ls1
INNER JOIN XML_Columns_Reference r1
ON sys.columns.name=r1.columnname
WHERE object_id = OBJECT_ID('TestXML') and r1.TableNameXML='T'
and ls1.PID=#PID and ls1.ID=ls2.ID and r1.GroupName=r2.GroupName
and r1.ColumnName NOT IN (SELECT [ColumnName]
FROM XML_NoUseCols_Ref
WHERE TableNameXML='T' and [Code]=ls1.Code
GROUP BY ColumnName)
ORDER BY column_id
FOR XML PATH(''),TYPE
)
FROM TestXML ls2
WHERE ls2.PID=#PID
FOR XML PATH('cat'),TYPE
)
FROM sys.columns
CROSS JOIN TestXML ls3
INNER JOIN XML_Columns_Reference r2
ON sys.columns.name=r2.columnname
WHERE object_id = OBJECT_ID('TestXML') and ls3.PID=#PID and r2.TableNameXML='T'
GROUP BY GroupName
ORDER BY MIN(groupOrder)
FOR XML PATH('grp'),TYPE
Result:
What I need is when there is a reference in XML_NoUseCols_Ref for all the rows of a group (you can get group in XML_Columns_Reference) to eliminated the cat row in the XML.
In the example that would be cat n="30" in grp n="A"
Any kind of help would be appreciated.
Thank you.
Instead of repeating the logic in many places I'd suggest to use a CTE (something like an ad-hoc VIEW) to pre-fetch your data. The rest is rather simple nesting with correlated sub-queries and much better to read:
Hope I got your logic correctly...
WITH cte AS
(
SELECT ls1.ID,ls1.PID,ls1.Code
,r1.ColumnNameXML,r1.GroupName,r1.GroupOrder
,CASE name
WHEN 'Col1' THEN ISNULL(Col1,0)
WHEN 'Col2' THEN ISNULL(Col2,0)
WHEN 'Col3' THEN ISNULL(Col3,0)
WHEN 'Col4' THEN ISNULL(Col4,0)
WHEN 'Col5' THEN ISNULL(Col5,0)
END AS ColumnValue
FROM sys.columns
CROSS JOIN TestXML ls1
INNER JOIN XML_Columns_Reference r1
ON sys.columns.name=r1.columnname
WHERE object_id = OBJECT_ID('TestXML') and r1.TableNameXML='T'
and ls1.PID=#PID
and r1.ColumnName NOT IN ( SELECT [ColumnName]
FROM XML_NoUseCols_Ref
WHERE TableNameXML='T' and [Code]=ls1.Code
GROUP BY ColumnName)
)
SELECT GroupName AS [#n]
,(
SELECT Code AS [#n]
,(
SELECT cte3.ColumnNameXML AS [#n]
,cte3.ColumnValue AS [col_value]
FROM cte cte3
WHERE cte3.GroupName=cte1.GroupName AND cte3.Code=cte2.Code
ORDER BY cte3.ColumnNameXML
FOR XML PATH('col'),TYPE
)
FROM cte cte2
WHERE cte1.GroupName=cte2.GroupName
GROUP BY cte2.Code
ORDER BY cte2.Code
FOR XML PATH('cat'),TYPE
)
FROM cte cte1
GROUP BY GroupName,GroupOrder
ORDER BY GroupOrder
FOR XML PATH('grp');

Cardinality Estimate warning when a function(IS_MEMBER ) is used in where clause in SQLServer

Consider the following Scenarios
Test data
CREATE TABLE T1 (
COL1 numeric (6, 0) NOT NULL,
COL2 numeric (18, 0) NOT NULL,
COL3 numeric (18, 0) NOT NULL,
COL4 numeric (5, 0) NOT NULL,
COL5 numeric (18, 0) NOT NULL,
COL6 varchar (20) NOT NULL,
COL7 varchar (50) NULL,
COL8 numeric (1, 0) NULL,
COL9 numeric (18, 0) NULL,
COL10 varchar (20) NULL
)
ALTER TABLE T1
ADD PRIMARY KEY ( COL1,COL2, COL3, COL4, COL5, COL6 )
INSERT INTO T1 VALUES (1, 2, 12, 1, 11, 'COL_1', '000002', 0, NULL, 'admin_group')
INSERT INTO T1 VALUES (1, 2, 12, 1, 11, 'COL_2', '000002', 0, NULL, 'admin_group')
INSERT INTO T1 VALUES (1, 2, 12, 1, 11, 'COL_3', '000002', 0, NULL, 'QABrowns')
INSERT INTO T1 VALUES (1, 2, 12, 1, 11, 'COL_4', '000002', 0, NULL, 'QABrowns')
INSERT INTO T1 VALUES (1, 2, 12, 1, 11, 'COL_5', '000002', 0, NULL, 'QABrowns')
INSERT INTO T1 VALUES (1, 2, 12, 1, 11, 'COL_6', '000002', 0, NULL, 'QABrowns')
INSERT INTO T1 VALUES (1, 2, 12, 1, 11, 'COL_7', '000002', 0, NULL, 'QABrowns')
INSERT INTO T1 VALUES (1, 2, 12, 1, 11, 'COL_8', '000002', 0, NULL, 'SuperUser')
INSERT INTO T1 VALUES (1, 2, 12, 1, 11, 'COL_9', '000002', 0, NULL, 'SuperUser')
INSERT INTO T1 VALUES (1, 2, 12, 1, 11, 'COL_10', '000002', 0, NULL, 'SuperUser')
INSERT INTO T1 VALUES (1, 2, 12, 1, 11, 'COL_11', '000002', 0, NULL, 'LOLCOP2')
INSERT INTO T1 VALUES (1, 2, 12, 1, 11, 'COL_12', '000002', 0, NULL, 'LOLCOP2')
INSERT INTO T1 VALUES (1, 2, 12, 1, 11, 'COL_13', '000002', 0, NULL, 'LOLCOP2')
INSERT INTO T1 VALUES (1, 2, 12, 1, 11, 'COL_14', '000002', 0, NULL, 'LOLCOP2')
Scenario 1:
SELECT T1.* from T1
WHERE IS_MEMBER( COL10)=1
--Execution Plan warning--
"Type conversion in expression (CONVERT_IMPLICIT(nvarchar(20),[V9WEBDB1].[V9WEBDB1].[T3].[COL10],0)) may affect "CardinalityEstimate" in query plan choice"
Scenario 2
SELECT * INTO T3 FROM T1 WHERE COL10 IN ('admin_group')
ALTER TABLE T3
ADD PRIMARY KEY ( COL1,COL2, COL3, COL4, COL5, COL6 )
UPDATE STATISTICS T3
INSERT INTO T3 SELECT * FROM T1 WHERE COL10 IN ('LOLCOP2','QABrowns','SuperUser')
UPDATE STATISTICS T3
SELECT T3.* from T3
WHERE IS_MEMBER( COL10)=1
--Execution Plan warnings :
"Type conversion in expression (CONVERT_IMPLICIT(nvarchar(20),[V9WEBDB1].[V9WEBDB1].[T3].[COL10],0)) may affect "CardinalityEstimate" in query plan choice"
Scenario 3
SELECT * INTO T4 FROM T1 WHERE COL10 IN ('admin_group')
ALTER TABLE T4
ADD PRIMARY KEY ( COL1,COL2, COL3, COL4, COL5, COL6 )
UPDATE STATISTICS T4
SELECT T4.* from T4
WHERE IS_MEMBER( COL10)=1
Execution Plan warnings--None
INSERT INTO T4 SELECT * FROM T1 WHERE COL10 IN ('LOLCOP2','QABrowns','SuperUser')
UPDATE STATISTICS T4
SELECT T4.* from T4
WHERE IS_MEMBER( COL10)=1
Execution Plan warnings--None
ASK:
In 1st and 2nd scenarios
SELECT T1.* from T1 WHERE IS_MEMBER( COL10)=1
sql gives bellow warning
"Type conversion in expression (CONVERT_IMPLICIT(nvarchar(20),[V9WEBDB1].[V9WEBDB1].[T3].[COL10],0)) may affect "CardinalityEstimate" in query plan choice"
But in 3rd scenario
SELECT T1.* from T1 WHERE IS_MEMBER( COL10)=1
sql does not gives any warnings.
Data type of COL10 is varchar(20).
Server Collation : SQL_Latin1_General_CP1_CI_AS
1) Why does this warning happens?
2) How to avoid above warning?
1) Why does this warning happens?
Your table column col10 is varchar(20) but IS_MEMBER() accepts sysname as a parameter, so the server converts your varchar(20) to nvarchar(20) (sysname is nvarchar(128))
2) How to avoid above warning?
Change your col10 type to sysname or at least to nvarchar(20)

return parent-chain ids of self-reference MSSQL table

I want to get the parent-chain from a child record. NOT ALL the children of a parent or an entire hierarchy.
looking here: https://learn.microsoft.com/en-us/sql/t-sql/queries/with-common-table-expression-transact-sql
at point "F. Using a recursive common table expression to display a hierarchical list" This is CLOSE to what I want to do but need just the parentage (list of IDs) for a single child row.
Here is my data:
CREATE TABLE dbo.Stuff
(StuffID int PRIMARY KEY NOT NULL,
ParentID int NULL,
[Name] varchar(25) NOT NULL,
[Desc] text NULL)
GO
insert dbo.stuff (StuffID, ParentID, [Name], [Desc])
VALUES (1, null, 'My Home', '1203 WoodHaven Rd')
insert dbo.stuff (StuffID, ParentID, [Name], [Desc])
VALUES (2, 1, 'Basement', 'Walkout basement')
insert dbo.stuff (StuffID, ParentID, [Name], [Desc])
VALUES (3, 1, 'Level 1', 'Family room')
insert dbo.stuff (StuffID, ParentID, [Name], [Desc])
VALUES (4, 1, 'Level 2', 'Living/Kitchen')
insert dbo.stuff (StuffID, ParentID, [Name], [Desc])
VALUES (5, 1, 'Level 3', 'Bedrooms & Laundry')
insert dbo.stuff (StuffID, ParentID, [Name], [Desc])
VALUES (6, 1, 'Attic', 'attic space')
insert dbo.stuff (StuffID, ParentID, [Name], [Desc])
VALUES (7, 2, 'Family Room', 'Family game room')
insert dbo.stuff (StuffID, ParentID, [Name], [Desc])
VALUES (8, 2, 'Storeroom', 'Storage room')
insert dbo.stuff (StuffID, ParentID, [Name], [Desc])
VALUES (9, 2, 'Furnace', 'Furnace/Server room')
insert dbo.stuff (StuffID, ParentID, [Name], [Desc])
VALUES (10, 7, 'Closet', 'Under stairs junk closet')
insert dbo.stuff (StuffID, ParentID, [Name], [Desc])
VALUES (11, 9, 'Furnace floor', 'Furnace Room Floor (under desk)')
insert dbo.stuff (StuffID, ParentID, [Name], [Desc])
VALUES (12, 9, 'Furnace keyboard Shelf', 'Furnace room name desk shelf')
insert dbo.stuff (StuffID, ParentID, [Name], [Desc])
VALUES (13, 9, 'Furnace High Shelf', 'Furnace/Server room high shelf')
insert dbo.stuff (StuffID, ParentID, [Name], [Desc])
VALUES (14, 13, 'Router', 'ASUS AC router')
insert dbo.stuff (StuffID, ParentID, [Name], [Desc])
VALUES (15, 13, 'Deprecated server', 'Old WinServer')
I want to know where the 'Router' is. The result I expect is:
1
2
9
13
14
and I would probably search for it by partial name:
WHERE [Name] LIKE '%rout%'
;with parents as
(
select
StuffID, ParentID
from
[Stuff]
WHERE
[Name] LIKE '%rout%'
union all
select
s.StuffID, s.ParentID
from
[Stuff] s
join parents p on
s.StuffID = p.ParentID
)
SELECT
StuffID
from
parents
order by
StuffID
The output will be: 1 2 7 13 14 (differs from your expectation 1 2 9 13 14, is that a mistake?)

How to output using recursive (parents -> children -> grandchildren)

CREATE TABLE PERSON
(
persID INT IDENTITY(1,1) PRIMARY KEY,
persFName VARCHAR(30) NOT NULL,
persLName VARCHAR(30) NOT NULL,
persDOB DATE,
motherID INT FOREIGN KEY REFERENCES person(persID),
fatherID INT FOREIGN KEY REFERENCES person(persID),
persDOD DATE,
persGender CHAR(1),
)
CREATE TABLE COUPLE
(
coupleID INT IDENTITY(1,1) PRIMARY KEY,
alphaSpouse INT NOT NULL FOREIGN KEY REFERENCES person(persID),
omegaSpouse INT NOT NULL FOREIGN KEY REFERENCES person(persID),
coupleStart DATE NOT NULL,
coupleEnd DATE,
)
INSERT INTO person (persFName, persLName, persDOB, motherID, fatherID, persDOD, persGender) VALUES
('Jim', 'Smith', '1920-05-15', NULL, NULL, '2001-04-21','M'),
('Agnes', 'Smith', '1922-09-21', NULL, NULL, '2003-06-01','F'),
('Linda', 'Howard', '1949-03-20', 2, 1, NULL,'F'),
('Helen', 'Bradley', '1942-11-28', 2, 1, NULL,'F'),
('Jim', 'Smith', '1953-02-10', 2, 1, NULL,'M'),
('Stephen', 'Smith', '1957-01-13', 2, 1, '2005-05-25','M'),
('Daniel', 'Smith', '1961-11-28', 2, 1, NULL,'M'),
('Michelle', 'Smith', '1963-07-02', NULL, NULL, NULL,'F'),
('Anne', 'Smith', '1958-04-22', NULL, NULL, NULL,'F'),
('Josh', 'Smith', '1990-01-28', 8, 7, NULL,'M'),
('Stephanie', 'Smith', '1992-05-18', 8, 7, NULL,'F'),
('Rachel', 'Smith', '1996-11-05', 8, 7, NULL,'F'),
('Reg', 'Howard', '1949-07-07', NULL, NULL, NULL,'M'),
('Richard', 'Howard', '1972-12-26', 3, 13, NULL,'M'),
('Phillip', 'Howard', '1975-06-01', 3, 13, NULL,'M'),
('Robert', 'Bradley', '1939-03-07', NULL, NULL, NULL,'M'),
('Matthew', 'Bradley', '1964-10-26', 4, 16, '2001-04-27','M'),
('Yvonne', 'Bradley', '1966-11-28', 4, 16, NULL,'F'),
('James', 'Bradley', '1971-01-26', 4, 16, NULL,'M'),
('Anna', 'Reuper', '1918-01-27', NULL, NULL, NULL,'F'),
('Ludwig', 'Reuper', '1923-07-01', NULL, NULL, '2001-07-01','M'),
('Heinz', 'Reuper', '1965-01-28', 20, 21, NULL,'M'),
('Veronica', 'Reuper', '1959-04-01', 20, 21, NULL,'F'),
('Marco', 'Johnson', '1958-09-04', NULL, NULL, NULL,'M'),
('Francesca', 'Reuper', '1990-11-01', 23, 24, NULL,'F'),
('Lou', 'Jung', '1940-02-03', NULL, NULL, NULL,'M'),
('Tammi', 'Sinclair', '1971-02-03', NULL, NULL, NULL,'F'),
('Lori', 'Navarro', '1973-12-15', NULL, NULL, NULL,'F'),
('Kattie', 'Paine', '1980-10-31', NULL, NULL, NULL,'F');
INSERT INTO couple (alphaSpouse,omegaSpouse, coupleStart, coupleEnd) VALUES
(1,2,'1940-05-22', NULL),
(3,13,'1969-07-30', '1973-10-01'),
(3,26,'1980-01-10', '1982-12-01'),
(4,16,'1963-04-05', NULL),
(6,9,'1979-06-21', NULL),
(7,8,'1987-09-14', NULL),
(20,21,'1936-10-26', NULL),
(23,24,'1988-05-01', '1997-07-01'),
(19,27,'1992-10-31', '1993-01-31'),
(19,28,'1995-08-18', '1997-04-27'),
(19,29,'2015-09-19', NULL);
I'm trying to list all the people who have grandchildren and how many grandchildren they each have. I'd like an ouput like this;
I attempted to do it below, but I got stuck trying to COUNT grandkids outside the WHERE subquery.. was I even on the right track?
SELECT grandp.persFName + ' ' + grandp.persLName, COUNT(grandkids.persID)
FROM person grandp
JOIN person child ON grandp.persID = child.motherID OR grandp.persID = child.fatherID
WHERE child.persID IN (SELECT grandkids.motherID
FROM person grandkids
union
SELECT grandkids.fatherID
FROM person grandkids)
GROUP BY grandp.persFName + ' ' + grandp.persLName
When you have hierarchical data like yours, it's best approached with common table expressions. This will allow you to build the hierarchical data into a form that you can later use - in your example, to count grandchildren. You can take advantage of building data by levels or distance from the root.
with temp (persid, ancestorid, level) as (
select persid, persid as ancestorid, 0 as level
from person
where motherid is null and fatherid is null
union all
select person.persid, temp.ancestorid, temp.level + 1 as level
from person
inner join temp on temp.persid = person.motherid or temp.persid = person.fatherid
)
select temp.ancestorid as persid,
person.persFName + ' ' + person.persLName as name,
count(*)
from temp
inner join person
on temp.ancestorid = person.persid
where level = 2
group by temp.ancestorid, person.persFName, person.persLName
The query builds a CTE of each person, it's ancestor and the level (0 = grandparents, 2 = grandchildren). You can then easily count grandchildren for each ancestor.
SQL Fiddle: http://sqlfiddle.com/#!3/99c97/2
(Note: I left the couple table out as it's not needed here).
Try this I just used common table expressions recursively to get the result
;WITH Allpersons AS
(
SELECT persID AS Id
,persFName+' '+persLName AS Name
,fatherID
,motherID
FROM PERSON
)
SELECT
GrandFatherCTE.Name
,COUNT(GrandFatherCTE.Id ) AS CountOfChild
FROM Allpersons AllPersonsCTE
INNER JOIN
Allpersons ParentsCte
ON
AllPersonsCTE.fatherID = ParentsCte.Id
OR
AllPersonsCTE.motherID = ParentsCte.Id
INNER JOIN
Allpersons GrandFatherCTE
ON
ParentsCte.fatherID = GrandFatherCTE.Id
OR
ParentsCte.motherID = GrandFatherCTE.Id
INNER JOIN
COUPLE
ON
GrandFatherCTE.Id = COUPLE.alphaSpouse
OR
GrandFatherCTE.Id = COUPLE.omegaSpouse
GROUP BY
GrandFatherCTE.Name
,COUPLE.coupleID
ORDER BY
CountOfChild ASC
,COUPLE.coupleID ASC

Resources