How to query SQL dynamic lookup - sql

I have to pull data from these tables
**PRODUCT** **LOOKUP_CATEGORY**
ID ProductName ID Category
1 Memory1 1 Product Type
2 Memory2 2 DIMM Type
3 Headset1 3 Color
4 Headset2 4 Speed
5 Keyboard1 5 Form Factor
6 Keyboard2
**LOOKUP**
ID CategoryID Value
1 1 DRAM
2 1 Keyboard
3 1 Headset
4 2 Buffered
5 2 Unbuffered
6 3 Red
7 3 White
8 3 Yellow
9 4 2000Mhz
10 4 2300Mhz
11 4 2600Mhz
12 5 DIMM
13 5 SODIMM
14 5 Earbud
15 5 On-Ear
**PRODUCT_FEATURES**
ID ProductID LookupID
1 1 1
2 1 4
3 1 10
4 1 12
5 2 1
6 2 5
7 2 9
8 2 13
9 3 3
10 3 7
11 3 15
12 4 3
13 4 6
14 4 14
15 5 2
16 5 7
17 6 2
18 6 8
I would like to get the result set like this
ProductName Type DIMMType Color Speed FormFactor
Memory1 DRAM Buffered NULL 2300Mhz DIMM
Memory2 DRAM Unbuffered NULL 2000Mhz SODIMM
Headset1 Headset NULL White NULL On-Ear
Headset2 Headset NULL Red NULL Earbud
Keyboard1 Keyboard NULL White NULL NULL
Keyboard2 Keyboard NULL Yellow NULL NULL
Basically, I would like to be able to get all the products.
How do I this without making function calls? My database is Microsoft SQL 2016
I have tried this, but it does not seem to work as expected because of those NULL values
Select p.ProductID, p.ProductNumber
, lType.Value AS ProductType, lDimm.Value AS DimmType, lSpeed.Value AS Speed, lColor.Value AS Color, lFactor.Value AS FormFactor
From PRODUCT p
Left Join PRODUCT_FEATURES xType On p.ProductID = xType.ProductID
Inner Join LOOKUP lType On xType.LookupID = lType.LookupID
Inner Join LOOKUP_CATEGORY lcType On lType.CategoryID = lcType.LookupCategoryID And lcType.Category = 'Product Type'
Left Join PRODUCT_FEATURES xDimm On p.ProductID = xDimm.ProductID
Inner Join LOOKUP lDimm On xDimm.LookupID = lDimm.LookupID
Inner Join LOOKUP_CATEGORY lcDimm On lDimm.CategoryID = lcDimm.LookupCategoryID And lcDimm.Category = 'DIMM Type'
Left Join PRODUCT_FEATURES xSpeed On p.ProductID = xSpeed.ProductID
Inner Join LOOKUP lSpeed On xSpeed.LookupID = lSpeed.LookupID
Inner Join LOOKUP_CATEGORY lcSpeed On lSpeed.CategoryID = lcSpeed.LookupCategoryID And lcSpeed.Category = 'Speed'
Left Join PRODUCT_FEATURES xColor On p.ProductID = xColor.ProductID
Inner Join LOOKUP lColor On xColor.LookupID = lColor.LookupID
Inner Join LOOKUP_CATEGORY lcColor On lColor.CategoryID = lcColor.LookupCategoryID And lcColor.Category = 'Color'
Left Join PRODUCT_FEATURES xFactor On p.ProductID = xFactor.ProductID
Inner Join LOOKUP lFactor On xFactor.LookupID = lFactor.LookupID
Inner Join LOOKUP_CATEGORY lcFactor On lFactor.CategoryID = lcFactor.LookupCategoryID And lcFactor.Category = 'Form Factor'

Grouping might be able to simplify it a bit.
SELECT
f.ProductID,
p.ProductName,
MAX(CASE WHEN lc.Category = 'Product Type' THEN l.Value END) AS ProductType,
MAX(CASE WHEN lc.Category = 'DIMM Type' THEN l.Value END) AS DimmType,
MAX(CASE WHEN lc.Category = 'Speed' THEN l.Value END) AS Speed,
MAX(CASE WHEN lc.Category = 'Color' THEN l.Value END) AS Color,
MAX(CASE WHEN lc.Category = 'Form Factor' THEN l.Value END) AS FormFactor
FROM PRODUCT_FEATURES f
LEFT JOIN PRODUCT p ON p.ID = f.ProductID
LEFT JOIN LOOKUP l ON l.ID = f.LookupID
LEFT JOIN LOOKUP_CATEGORY lc ON lc.ID = l.CategoryID
GROUP BY f.ProductID, p.ProductName

You could also write it as below, if you want it truely to be dynamic you'd have to generate the statement below using dynamic SQL techniques, see SQL Server dynamic PIVOT query?:
Select ProductId,
ProductName,
Test.[Product type],
Test.[DIMM Type],
Test.[Speed],
Test.[Color],
Test.[Form Factor]
From
(SELECT
P.ProductID,
p.ProductName,
Category,
value
FROM imp.PRODUCT_FEATURES f
LEFT JOIN imp.PRODUCT p ON p.productID = f.ProductID
LEFT JOIN imp.LOOKUP l ON l.lookupID = f.LookupID
LEFT JOIN imp.LOOKUP_CATEGORY lc ON lc.lookupcategoryID = l.CategoryID
) dt
pivot (max(dt.[value]) for dt.[CATEGORY] in ([Product type],[DIMM Type],[Speed],[Color],[Form Factor])) as test
For convenience..
--Create the schema IMP first..
/****** Object: Table [imp].[Lookup] Script Date: 8/1/2018 1:48:28 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [imp].[Lookup](
[lookupID] [float] NULL,
[CategoryID] [float] NULL,
[Value] [nvarchar](255) NULL
) ON [PRIMARY]
GO
/****** Object: Table [imp].[Lookup_category] Script Date: 8/1/2018 1:48:28 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [imp].[Lookup_category](
[lookupcategoryID] [float] NULL,
[Category] [nvarchar](255) NULL
) ON [PRIMARY]
GO
/****** Object: Table [imp].[Product] Script Date: 8/1/2018 1:48:28 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [imp].[Product](
[ProductID] [float] NULL,
[ProductName] [nvarchar](255) NULL
) ON [PRIMARY]
GO
/****** Object: Table [imp].[Product_features] Script Date: 8/1/2018 1:48:28 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [imp].[Product_features](
[ID] [float] NULL,
[ProductID] [float] NULL,
[LookupID] [float] NULL
) ON [PRIMARY]
GO
INSERT [imp].[Lookup] ([lookupID], [CategoryID], [Value]) VALUES (1, 1, N'DRAM')
GO
INSERT [imp].[Lookup] ([lookupID], [CategoryID], [Value]) VALUES (2, 1, N'Keyboard')
GO
INSERT [imp].[Lookup] ([lookupID], [CategoryID], [Value]) VALUES (3, 1, N'Headset')
GO
INSERT [imp].[Lookup] ([lookupID], [CategoryID], [Value]) VALUES (4, 2, N'Buffered')
GO
INSERT [imp].[Lookup] ([lookupID], [CategoryID], [Value]) VALUES (5, 2, N'Unbuffered')
GO
INSERT [imp].[Lookup] ([lookupID], [CategoryID], [Value]) VALUES (6, 3, N'Red')
GO
INSERT [imp].[Lookup] ([lookupID], [CategoryID], [Value]) VALUES (7, 3, N'White')
GO
INSERT [imp].[Lookup] ([lookupID], [CategoryID], [Value]) VALUES (8, 3, N'Yellow')
GO
INSERT [imp].[Lookup] ([lookupID], [CategoryID], [Value]) VALUES (9, 4, N'2000Mhz')
GO
INSERT [imp].[Lookup] ([lookupID], [CategoryID], [Value]) VALUES (10, 4, N'2300Mhz')
GO
INSERT [imp].[Lookup] ([lookupID], [CategoryID], [Value]) VALUES (11, 4, N'2600Mhz')
GO
INSERT [imp].[Lookup] ([lookupID], [CategoryID], [Value]) VALUES (12, 5, N'DIMM')
GO
INSERT [imp].[Lookup] ([lookupID], [CategoryID], [Value]) VALUES (13, 5, N'SODIMM')
GO
INSERT [imp].[Lookup] ([lookupID], [CategoryID], [Value]) VALUES (14, 5, N'Earbud')
GO
INSERT [imp].[Lookup] ([lookupID], [CategoryID], [Value]) VALUES (15, 5, N'On-Ear')
GO
INSERT [imp].[Lookup_category] ([lookupcategoryID], [Category]) VALUES (1, N'Product Type')
GO
INSERT [imp].[Lookup_category] ([lookupcategoryID], [Category]) VALUES (2, N'DIMM Type')
GO
INSERT [imp].[Lookup_category] ([lookupcategoryID], [Category]) VALUES (3, N'Color')
GO
INSERT [imp].[Lookup_category] ([lookupcategoryID], [Category]) VALUES (4, N'Speed')
GO
INSERT [imp].[Lookup_category] ([lookupcategoryID], [Category]) VALUES (5, N'Form Factor')
GO
INSERT [imp].[Product] ([ProductID], [ProductName]) VALUES (1, N'Memory1')
GO
INSERT [imp].[Product] ([ProductID], [ProductName]) VALUES (2, N'Memory2')
GO
INSERT [imp].[Product] ([ProductID], [ProductName]) VALUES (3, N'Headset1')
GO
INSERT [imp].[Product] ([ProductID], [ProductName]) VALUES (4, N'Headset2')
GO
INSERT [imp].[Product] ([ProductID], [ProductName]) VALUES (5, N'Keyboard1')
GO
INSERT [imp].[Product] ([ProductID], [ProductName]) VALUES (6, N'Keyboard2')
GO
INSERT [imp].[Product_features] ([ID], [ProductID], [LookupID]) VALUES (1, 1, 1)
GO
INSERT [imp].[Product_features] ([ID], [ProductID], [LookupID]) VALUES (2, 1, 4)
GO
INSERT [imp].[Product_features] ([ID], [ProductID], [LookupID]) VALUES (3, 1, 10)
GO
INSERT [imp].[Product_features] ([ID], [ProductID], [LookupID]) VALUES (4, 1, 12)
GO
INSERT [imp].[Product_features] ([ID], [ProductID], [LookupID]) VALUES (5, 2, 1)
GO
INSERT [imp].[Product_features] ([ID], [ProductID], [LookupID]) VALUES (6, 2, 5)
GO
INSERT [imp].[Product_features] ([ID], [ProductID], [LookupID]) VALUES (7, 2, 9)
GO
INSERT [imp].[Product_features] ([ID], [ProductID], [LookupID]) VALUES (8, 2, 13)
GO
INSERT [imp].[Product_features] ([ID], [ProductID], [LookupID]) VALUES (9, 3, 3)
GO
INSERT [imp].[Product_features] ([ID], [ProductID], [LookupID]) VALUES (10, 3, 7)
GO
INSERT [imp].[Product_features] ([ID], [ProductID], [LookupID]) VALUES (11, 3, 15)
GO
INSERT [imp].[Product_features] ([ID], [ProductID], [LookupID]) VALUES (12, 4, 3)
GO
INSERT [imp].[Product_features] ([ID], [ProductID], [LookupID]) VALUES (13, 4, 6)
GO
INSERT [imp].[Product_features] ([ID], [ProductID], [LookupID]) VALUES (14, 4, 14)
GO
INSERT [imp].[Product_features] ([ID], [ProductID], [LookupID]) VALUES (15, 5, 2)
GO
INSERT [imp].[Product_features] ([ID], [ProductID], [LookupID]) VALUES (16, 5, 7)
GO
INSERT [imp].[Product_features] ([ID], [ProductID], [LookupID]) VALUES (17, 6, 2)
GO
INSERT [imp].[Product_features] ([ID], [ProductID], [LookupID]) VALUES (18, 6, 8)
GO

Related

Get multiple records between particular start and end point in the table

I have table data like below
In the given table, some records are outdated data that is generated by a bug in a system.
I want to remove all the outdated records
Correct data condition:
if itemStatus rows start and end from status 4 and 6 without 13 or 14 status then it is correct. I do not need to delete that row.
Example: Id 18 to 20 that are correct data.
Note: Id 21 and 22 is correct because status 13,14 start after status 6 (id 20)
Incorrect data conditions:
If itemStatus row starts and ends from status 4 and 6, with 13 and 14 status. Then it is incorrect data and I have to delete that from a DB.
Example: 24 and 25 then 29 and 30
My query
IF OBJECT_ID('tempdb..#TempResult') IS NOT NULL DROP TABLE #TempResult
CREATE TABLE #TempResult (
Id int
)
select ItemId
into #TempItemGroup
from Item
group by itemid
declare #SelectedItemId int
while exists (select ItemId from #TempItemGroup)
begin
select #SelectedItemId = (select top 1 ItemId
from #TempItemGroup
order by ItemId asc
)
IF OBJECT_ID('tempdb..#TempSingleItemGroup') IS NOT NULL DROP TABLE #TempSingleItemGroup
SELECT i1.*
into #TempSingleItemGroup
FROM Item i1
WHERE i1.[Id] >= ( SELECT TOP 1 [Id] FROM Item
WHERE [ItemStatus] = 4 and ItemId = #SelectedItemId )
AND i1.[Id] <= ( SELECT TOP 1 [Id] FROM Item
WHERE [ItemStatus] = 6 and ItemId = #SelectedItemId )
INSERT INTO #TempResult (Id) (SELECT Id FROM #TempSingleItemGroup where ItemStatus = 13 or ItemStatus = 14)
IF OBJECT_ID('tempdb..#TempSingleItemGroup') IS NOT NULL DROP TABLE #TempSingleItemGroup
delete #TempItemGroup
where ItemId = #SelectedItemId
end
-- Delete or do other operation if required
IF(EXISTS(SELECT count(Id) FROM #TempResult))
BEGIN
-- write a query to delete the data
select * from #TempResult
END
IF OBJECT_ID('tempdb..#TempResult') IS NOT NULL DROP TABLE #TempResult
IF OBJECT_ID('tempdb..#TempItemGroup') IS NOT NULL DROP TABLE #TempItemGroup
Expected result
There are some differences between screenshot and actual table data that you can find at the end of this question
Screenshot: 24,25,29,30
Table data: 13,14,15 ,26,27, 31,32
I have two queries
My above query is only getting first status which have 4 and 6
status, example Id 24 and 25, and I am unable to get next wrong
data for 29 and 30
I am using while loop that may not a good
practices. Please suggest me a better way to write a query.
Table schema and data
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Item](
[Id] [int] IDENTITY(1,1) NOT NULL,
[ItemId] [int] NOT NULL,
[ItemStatus] [int] NOT NULL,
CONSTRAINT [PK_Item] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO
SET IDENTITY_INSERT [dbo].[Item] ON
GO
INSERT [dbo].[Item] ([Id], [ItemId], [ItemStatus]) VALUES (1, 23, 2)
GO
INSERT [dbo].[Item] ([Id], [ItemId], [ItemStatus]) VALUES (2, 23, 4)
GO
INSERT [dbo].[Item] ([Id], [ItemId], [ItemStatus]) VALUES (3, 23, 7)
GO
INSERT [dbo].[Item] ([Id], [ItemId], [ItemStatus]) VALUES (4, 23, 6)
GO
INSERT [dbo].[Item] ([Id], [ItemId], [ItemStatus]) VALUES (5, 23, 13)
GO
INSERT [dbo].[Item] ([Id], [ItemId], [ItemStatus]) VALUES (6, 23, 14)
GO
INSERT [dbo].[Item] ([Id], [ItemId], [ItemStatus]) VALUES (7, 23, 4)
GO
INSERT [dbo].[Item] ([Id], [ItemId], [ItemStatus]) VALUES (8, 23, 6)
GO
INSERT [dbo].[Item] ([Id], [ItemId], [ItemStatus]) VALUES (9, 23, 3)
GO
INSERT [dbo].[Item] ([Id], [ItemId], [ItemStatus]) VALUES (10, 45, 2)
GO
INSERT [dbo].[Item] ([Id], [ItemId], [ItemStatus]) VALUES (11, 45, 4)
GO
INSERT [dbo].[Item] ([Id], [ItemId], [ItemStatus]) VALUES (12, 45, 7)
GO
INSERT [dbo].[Item] ([Id], [ItemId], [ItemStatus]) VALUES (13, 45, 13)
GO
INSERT [dbo].[Item] ([Id], [ItemId], [ItemStatus]) VALUES (14, 45, 14)
GO
INSERT [dbo].[Item] ([Id], [ItemId], [ItemStatus]) VALUES (15, 45, 13)
GO
INSERT [dbo].[Item] ([Id], [ItemId], [ItemStatus]) VALUES (16, 45, 6)
GO
INSERT [dbo].[Item] ([Id], [ItemId], [ItemStatus]) VALUES (17, 45, 3)
GO
INSERT [dbo].[Item] ([Id], [ItemId], [ItemStatus]) VALUES (18, 25, 2)
GO
INSERT [dbo].[Item] ([Id], [ItemId], [ItemStatus]) VALUES (19, 25, 4)
GO
INSERT [dbo].[Item] ([Id], [ItemId], [ItemStatus]) VALUES (20, 25, 7)
GO
INSERT [dbo].[Item] ([Id], [ItemId], [ItemStatus]) VALUES (21, 25, 6)
GO
INSERT [dbo].[Item] ([Id], [ItemId], [ItemStatus]) VALUES (23, 25, 13)
GO
INSERT [dbo].[Item] ([Id], [ItemId], [ItemStatus]) VALUES (24, 25, 14)
GO
INSERT [dbo].[Item] ([Id], [ItemId], [ItemStatus]) VALUES (25, 25, 4)
GO
INSERT [dbo].[Item] ([Id], [ItemId], [ItemStatus]) VALUES (26, 25, 13)
GO
INSERT [dbo].[Item] ([Id], [ItemId], [ItemStatus]) VALUES (27, 25, 14)
GO
INSERT [dbo].[Item] ([Id], [ItemId], [ItemStatus]) VALUES (28, 25, 6)
GO
INSERT [dbo].[Item] ([Id], [ItemId], [ItemStatus]) VALUES (29, 25, 3)
GO
INSERT [dbo].[Item] ([Id], [ItemId], [ItemStatus]) VALUES (30, 25, 4)
GO
INSERT [dbo].[Item] ([Id], [ItemId], [ItemStatus]) VALUES (31, 25, 13)
GO
INSERT [dbo].[Item] ([Id], [ItemId], [ItemStatus]) VALUES (32, 25, 14)
GO
INSERT [dbo].[Item] ([Id], [ItemId], [ItemStatus]) VALUES (33, 24, 6)
GO
SET IDENTITY_INSERT [dbo].[Item] OFF
GO
My reading of your requirement is this:
For each itemId, find rows with itemStatus in (13, 14) that lie between a row with the same itemId and itemStatus 4, and a row with the same itemid and itemStatus 6, in order of id ascending.
Your current requirements do not state whether we should return rows with item status in (13, 14) where there is a prior 4 row, but no subsequent 6 row (the "end" of the itemid group is reached), or what to do if there is a subsequent 6 row, but no prior 4 row (the "start" of the itemid group is reached).
I make the following interpretation: itemStatus 4 opens a "status block". itemStatus 6 closes a "status block". There should be no rows with status 13 or 14 in an open block.
If that is a correct interpretation, all we really need to do is find rows with item status 13 or 14, and then find the nearest prior row in order of id descending with a status of either 4 or 6. If the status of that prior row is 4 then the rows are in an open block. If the status of that prior row is 6, or no prior row can be found, then the rows are not in an open block.
Note: In the comments you mentioned expected results including id 31 and 32. But your sample data does not include any row with id 31 or 32. You have now provided these rows and I have added them to my data.
create table #items
(
Id int primary key,
ItemId int not null,
ItemStatus int not null,
);
insert #items values
(2, 23, 4),
(3, 23, 7),
(4, 23, 6),
(5, 23, 13),
(6, 23, 14),
(7, 23, 4),
(8, 23, 6),
(9, 23, 3),
(10, 45, 2),
(11, 45, 4),
(12, 45, 7),
(13, 45, 13),
(14, 45, 14),
(15, 45, 13),
(16, 45, 6),
(17, 45, 3),
(18, 25, 2),
(19, 25, 4),
(20, 25, 7),
(21, 25, 6),
(23, 25, 13),
(24, 25, 14),
(25, 25, 4),
(26, 25, 13),
(27, 25, 14),
(28, 25, 6),
(29, 25, 3),
(30, 25, 4),
(31, 25, 13),
(32, 25, 14),
(33, 24, 6);
select item13or14.*
from #items item13or14
cross apply (
select top 1 itemStatus
from #items
where itemId = item13or14.itemId
and id < item13or14.id
and itemStatus in (4, 6)
order by id desc
) prior4or6
where item13or14.itemStatus in (13, 14)
and prior4or6.itemStatus = 4;
/* produces:
Id ItemId ItemStatus
13 45 13
14 45 14
15 45 13
26 25 13
27 25 14
31 25 13
32 25 14
*/

Sql Select using CTE to order a recursive data

Please i want a solution for this problem using CTE in SQL Server
Example for the situation
Equation 0 = 0.25*Equation 1
Equation 1 = Equation 2 + Equation 3 + 0.5*Equation 5
Equation 2 = 15 + 40
Equation 3 = Equation 6 + Equation 7
Equation 4 = 10
Equation 5 = 10 + Equation 4
Equation 6 = 10 +5
Equation 7 = Equation 5 + Equation 2
The structure of the tables is
The Element Table
ID | Name
-------|--------------
0 | Equation 0
1 | Equation 1
2 | Equation 2
3 | Equation 3
4 | Equation 4
5 | Equation 5
6 | Equation 6
7 | Equation 7
---------------------
the table holds all items of each equation
The equation Table
FK | Item | Type
-------|-----------|------------------
0 | 0.25 | constant
0 | * | Operator
0 | 1 | Element
1 | 2 | Element
1 | + | Operator
1 | 3 | Element
1 | + | Operator
1 | 0.5 | constant
1 | * | Operator
1 | 5 | Element
2 | 15 | constant
2 | + | Operator
2 | 40 | constant
… | |
… | |
… etc | |
------------------------------------
if the type is element this means it is an element item
is there any sql statement result to the correct order that i must use to calculate these equations one by one without using recursive functions because it is limited in SQL
the alternative is to calculate the last equation without any requirements then calculate the upper ones as when i need an equation i find it calculated already without recursing the equations
i need the sql select statement to produce the following order
Equation 2
Equation 6
Equation 4
Equation 5
Equation 7
Equation 3
Equation 1
Equation 0
i ordered them by eye because it is simple example
is there any select statement is used to do so
or the user must order them manually ???
... Update
1. with a fully working test scenario
The Script to create tables
/****** Object: Table [dbo].[Element] Script Date: 26/03/2017 11:10:10 م ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Element](
[Id] [int] NOT NULL,
[Name] [nvarchar](50) NOT NULL,
CONSTRAINT [PK_Element] PRIMARY KEY CLUSTERED
(
[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
/****** Object: Table [dbo].[Equation] Script Date: 26/03/2017 11:10:10 م ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Equation](
[fk] [int] NOT NULL,
[Item] [nvarchar](50) NOT NULL,
[Type] [nvarchar](50) NOT NULL
) ON [PRIMARY]
GO
INSERT [dbo].[Element] ([Id], [Name]) VALUES (0, N'Equation 0')
INSERT [dbo].[Element] ([Id], [Name]) VALUES (1, N'Equation 1')
INSERT [dbo].[Element] ([Id], [Name]) VALUES (2, N'Equation 2')
INSERT [dbo].[Element] ([Id], [Name]) VALUES (3, N'Equation 3')
INSERT [dbo].[Element] ([Id], [Name]) VALUES (4, N'Equation 4')
INSERT [dbo].[Element] ([Id], [Name]) VALUES (5, N'Equation 5')
INSERT [dbo].[Element] ([Id], [Name]) VALUES (6, N'Equation 6')
INSERT [dbo].[Element] ([Id], [Name]) VALUES (7, N'Equation 7')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (0, N'0.25', N'constant')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (0, N'*', N'Operator')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (0, N'1', N'Element')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (1, N'2', N'Element')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (1, N'+', N'Operator')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (1, N'3', N'Element')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (1, N'+', N'Operator')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (1, N'0.5', N'constant')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (1, N'*', N'Operator')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (1, N'5', N'Element')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (2, N'15', N'constant')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (2, N'+', N'Operator')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (2, N'40', N'constant')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (3, N'6', N'Element')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (3, N'+', N'Operator')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (3, N'7', N'Element')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (4, N'10', N'Constant')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (5, N'10', N'Constant')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (5, N'+', N'Operator')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (5, N'4', N'Element')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (6, N'10', N'Constant')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (6, N'+', N'Operator')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (6, N'5', N'Constant')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (7, N'5', N'Element')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (7, N'+', N'Operator')
INSERT [dbo].[Equation] ([fk], [Item], [Type]) VALUES (7, N'2', N'Element')
*
#Gordon Linoff
... Thanks a lot for your care but i found some errors using the provided script that i cant solve as it is the first time for me to use CTE
The second script gives me some errors that i cant solve
the first script gives me errors as well that i cant solve
You can try it like this:
WITH Related AS
(
SELECT *
FROM Equation AS eq
LEFT JOIN Element AS e ON eq.[Type]='Element' AND eq.Item=CAST(e.Id AS VARCHAR(10))
WHERE eq.[Type]='Element'
)
,Dependecies AS
(
SELECT e.*
,ISNULL(r.Name,'') AS DepName
FROM Element AS e
LEFT JOIN Related AS r ON e.Id=r.fk
)
,recCTE AS
(
SELECT 1 AS lvl,d.Id,d.Name,d.DepName
FROM Dependecies AS d
WHERE d.Name NOT IN(SELECT x.DepName FROM Dependecies AS x)
UNION ALL
SELECT r.lvl+1,d.Id,d.Name,d.DepName
FROM recCTE AS r
INNER JOIN Dependecies AS d ON r.DepName=d.Name
)
,Ranked AS
(
SELECT Name
,DENSE_RANK() OVER(ORDER BY CASE WHEN DepName='' THEN 1000 ELSE lvl END DESC) AS Rnk
FROM recCTE
)
SELECT Name,MIN(Rnk) AS Rnk
FROM Ranked
GROUP BY Name
ORDER BY Min(Rnk)
The result
Equation 2 1
Equation 4 1
Equation 6 1
Equation 5 2
Equation 7 3
Equation 3 4
Equation 1 5
Equation 0 6
Explanation
There is a list of CTEs:
The first CTE will bind the Elements to Equation rows, where the type is Element.
The second will list all Elements with their dependencies
The third CTE is a recursive CTE, starting with the element without any dependecies, working down the dependency path
The next CTE uses DENSE_RANK() OVER() to get the calls ordered
The final SELECT returns each element and the earliest moment it is needed.
Oh, it would be swell if we could express this as:
with cte as (
select e.fk, 1 as lev
from equation e
group by e.fk
having sum(case when type = 'Element' then 1 else 0 end) = 0
union all
select e.fk, max(cte.lev) + 1
from equation e left join
cte
on e.fk = cte.fk
group by e.fk
having count(*) = count(cte.fk)
)
But that is not possible. So, we have to think in terms of string manipulation (I think). This results in putting the dependencies in a string and repeatedly chopping elements off of the string. If I have this right:
with eq as (
select e.fk,
stuff( (select ',' + e2.item
from equation e2
where e2.fk = e.fk and e2.type = 'Element'
order by e2.item
for xml path ('')
), 1, 1, '') as elements
from (select distinct e.fk from equation e) e
)
select e.fk, '' as elements_found, 1 as lev
from eq
where elements = ''
union all
select eq.fk, substring(elements_found, charindex(',', elements_found + ',') + 1), 2 as lev
from eq join
cte
on cte.elements_found like eq.fk + ',%' and eq.fk = cte.fk
where eq.type = 'Element'
)
select cte.fk, max(lev)
from cte
group by cte.fk
order by max(lev);

Select from 3 tables (one to many, many to one relationship)

I have 3 tables:
Recipes (1 --- * ) Ingridients ( *---1) Products. I need to obtain Recipes that contains products in a given list or products that are not in list but have a specific flag set. I have a flag in product table (bool). So where clause looks like:
WHERE Product.Caption IN ('A', 'B', 'C') OR (Product.Caption NOT IN ('A', 'B', 'C') AND Product.Flag=TRUE)
Important is: I do not need recipes that contain products in list and also contain other products (not in list and flag is false).
Bellow is an example database dump for MSSQL:
USE [master]
IF EXISTS (SELECT * FROM master.dbo.sysdatabases WHERE name = N'movedb') ALTER DATABASE [movedb] SET SINGLE_USER With ROLLBACK IMMEDIATE
IF EXISTS (SELECT * FROM master.dbo.sysdatabases WHERE name = N'movedb') DROP DATABASE [movedb]
IF NOT EXISTS (SELECT * FROM master.dbo.sysdatabases WHERE name = N'movedb') CREATE DATABASE [movedb]
USE [movedb]
--
-- Table structure for table 'Ingridients'
--
IF object_id(N'Ingridients', 'U') IS NOT NULL DROP TABLE [Ingridients]
CREATE TABLE [Ingridients] (
[Id] INT NOT NULL IDENTITY,
[Quantity] INT DEFAULT 0,
[IdProduct] INT DEFAULT 0,
[IdRecipe] INT DEFAULT 0,
PRIMARY KEY ([Id])
)
SET IDENTITY_INSERT [Ingridients] ON
GO
--
-- Dumping data for table 'Ingridients'
--
INSERT INTO [Ingridients] ([Id], [Quantity], [IdProduct], [IdRecipe]) VALUES (1, 0, 1, 2)
INSERT INTO [Ingridients] ([Id], [Quantity], [IdProduct], [IdRecipe]) VALUES (2, 0, 3, 2)
INSERT INTO [Ingridients] ([Id], [Quantity], [IdProduct], [IdRecipe]) VALUES (3, 0, 4, 2)
INSERT INTO [Ingridients] ([Id], [Quantity], [IdProduct], [IdRecipe]) VALUES (4, 0, 6, 2)
INSERT INTO [Ingridients] ([Id], [Quantity], [IdProduct], [IdRecipe]) VALUES (5, 0, 2, 3)
INSERT INTO [Ingridients] ([Id], [Quantity], [IdProduct], [IdRecipe]) VALUES (6, 0, 4, 3)
INSERT INTO [Ingridients] ([Id], [Quantity], [IdProduct], [IdRecipe]) VALUES (7, 0, 8, 3)
INSERT INTO [Ingridients] ([Id], [Quantity], [IdProduct], [IdRecipe]) VALUES (8, 0, 1, 4)
INSERT INTO [Ingridients] ([Id], [Quantity], [IdProduct], [IdRecipe]) VALUES (9, 0, 6, 4)
INSERT INTO [Ingridients] ([Id], [Quantity], [IdProduct], [IdRecipe]) VALUES (10, 0, 5, 4)
-- 10 records
SET IDENTITY_INSERT [Ingridients] OFF
GO
--
-- Table structure for table 'Products'
--
IF object_id(N'Products', 'U') IS NOT NULL DROP TABLE [Products]
CREATE TABLE [Products] (
[Id] INT NOT NULL IDENTITY,
[Caption] NVARCHAR(255),
[EasyToFind] BIT DEFAULT 0,
PRIMARY KEY ([Id])
)
SET IDENTITY_INSERT [Products] ON
GO
--
-- Dumping data for table 'Products'
--
INSERT INTO [Products] ([Id], [Caption], [EasyToFind]) VALUES (1, N'ProductA', 0)
INSERT INTO [Products] ([Id], [Caption], [EasyToFind]) VALUES (2, N'ProductB', 0)
INSERT INTO [Products] ([Id], [Caption], [EasyToFind]) VALUES (3, N'ProductC', 0)
INSERT INTO [Products] ([Id], [Caption], [EasyToFind]) VALUES (4, N'ProductD', -1)
INSERT INTO [Products] ([Id], [Caption], [EasyToFind]) VALUES (5, N'ProductE', 0)
INSERT INTO [Products] ([Id], [Caption], [EasyToFind]) VALUES (6, N'ProductF', -1)
INSERT INTO [Products] ([Id], [Caption], [EasyToFind]) VALUES (7, N'ProductG', 0)
INSERT INTO [Products] ([Id], [Caption], [EasyToFind]) VALUES (8, N'ProductH', 0)
INSERT INTO [Products] ([Id], [Caption], [EasyToFind]) VALUES (9, N'ProductI', 0)
INSERT INTO [Products] ([Id], [Caption], [EasyToFind]) VALUES (10, N'ProductJ', 0)
-- 10 records
SET IDENTITY_INSERT [Products] OFF
GO
--
-- Table structure for table 'Recipes'
--
IF object_id(N'Recipes', 'U') IS NOT NULL DROP TABLE [Recipes]
CREATE TABLE [Recipes] (
[Id] INT NOT NULL IDENTITY,
[Caption] NVARCHAR(255),
PRIMARY KEY ([Id])
)
SET IDENTITY_INSERT [Recipes] ON
GO
--
-- Dumping data for table 'Recipes'
--
INSERT INTO [Recipes] ([Id], [Caption]) VALUES (2, N'RecipeA')
INSERT INTO [Recipes] ([Id], [Caption]) VALUES (3, N'RecipeB')
INSERT INTO [Recipes] ([Id], [Caption]) VALUES (4, N'RecipeC')
-- 3 records
SET IDENTITY_INSERT [Recipes] OFF
GO
Example:
If I search for ProductA and ProductE it should give me only RecipeC
Right now I have something like this for MySQL ( it is not final. I can only operate with Ids, I neet somehow to change it to work only with product captions and adapt for MSSQL)
SELECT
*
FROM
recipes AS r
INNER JOIN
ingridients i ON i.IdRecipe = r.Id
WHERE
i.IdProduct IN (1 , 5, 6)
GROUP BY r.Id
HAVING COUNT(*) = (SELECT
COUNT(*)
FROM
ingridients AS ing
WHERE
ing.IdRecipe = r.Id);
The following sql fetches the recipes that contains no products other than those in the list or having P.EasyToFind=-1.
select *
From Recipes
Where Id not in
(
select IdRecipe
from Ingridients I
inner join Products P ON I.IdProduct = P.Id
where P.Caption NOT IN ('ProductA','ProductE')
and P.EasyToFind=0
)
It works by having an inner query that identifies the unwanted ingredients and fetching the recipes that does not match any of them.

Hierarchical data with CTE

I am sorry if the answer has been posted already, but I was not able to find the answer even after searching.
I have the following table
CREATE TABLE [dbo].[emp](
[id] [int] NOT NULL,
[name] [varchar](20) NULL,
[mgrid] [int] NULL
) ON [PRIMARY]
With data
INSERT [dbo].[emp] ([id], [name], [mgrid]) VALUES (1, N'a', 0)
INSERT [dbo].[emp] ([id], [name], [mgrid]) VALUES (2, N'a1', 1)
INSERT [dbo].[emp] ([id], [name], [mgrid]) VALUES (3, N'a11', 2)
INSERT [dbo].[emp] ([id], [name], [mgrid]) VALUES (4, N'a12', 2)
INSERT [dbo].[emp] ([id], [name], [mgrid]) VALUES (5, N'a13', 2)
INSERT [dbo].[emp] ([id], [name], [mgrid]) VALUES (6, N'a2', 1)
INSERT [dbo].[emp] ([id], [name], [mgrid]) VALUES (7, N'a3', 1)
INSERT [dbo].[emp] ([id], [name], [mgrid]) VALUES (8, N'a31', 7)
INSERT [dbo].[emp] ([id], [name], [mgrid]) VALUES (9, N'a32', 7)
INSERT [dbo].[emp] ([id], [name], [mgrid]) VALUES (10, N'b', 0)
INSERT [dbo].[emp] ([id], [name], [mgrid]) VALUES (11, N'b1', 10)
INSERT [dbo].[emp] ([id], [name], [mgrid]) VALUES (12, N'b2', 10)
And I would like the following output
a
a1
a11
a12
a13
a2
a3
a31
a32
b
b1
b2
Is this possible in SQL Server?
SQLFiddle demo
You can use ' ' instead of '+' in the last line to pad a string.
with t as
(
select id,name,mgrid,1 as level,cast(name as varchar(max)) as path
from emp where mgrid=0
union all
select emp.id,emp.name,emp.mgrid, t.level+1 as level,
t.path+cast(emp.name as varchar(max)) as path
from emp
join t on emp.mgrid=t.id
)
select replicate('+', level)+name from t order by path
with CTE as
(
select *
, level = 1
from emp
where mgrid = 0
union all
select emp.id,
name = cast(space((level) * 3) + emp.name as varchar(20)),
emp.mgrid,
level = level + 1
from emp
inner join CTE on CTE.id = emp.mgrid
)
select name
from CTE
order by ltrim(name)
Query:
DECLARE #temp TABLE
(
[id] [int] NOT NULL,
[name] [varchar](20) NULL,
[mgrid] [int] NULL
)
INSERT INTO #temp ([id], [name], [mgrid])
VALUES
(1, N'a', 0), (2, N'a1', 1),
(3, N'a11', 2), (4, N'a12', 2),
(5, N'a13', 2), (6, N'a2', 1),
(7, N'a3', 1), (8, N'a31', 7),
(9, N'a32', 7), (10, N'b', 0),
(11, N'b1', 10), (12, N'b2', 10)
DECLARE #out VARCHAR(MAX) = ''
;WITH cte AS
(
SELECT *, Lvl = 0, nn = CAST(name AS VARCHAR(MAX))
FROM #temp
WHERE mgrid = 0
UNION ALL
SELECT t.*, c.Lvl + 1, nn = CAST(REPLICATE(' ', c.Lvl + 1) + t.name AS VARCHAR(MAX))
FROM #temp t
JOIN cte c ON c.id = t.mgrid
)
SELECT #out = (
SELECT nn + CHAR(13)
FROM cte
ORDER BY LTRIM(nn)
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)')
PRINT #out
Output:
a
a1
a11
a12
a13
a2
a3
a31
a32
b
b1
b2
You can use CTE (Comnon table expression to achieve this)
check this sample code:
declare #emp table(
[id] [int] NOT NULL,
[name] [varchar](20) NULL,
[mgrid] [int] NULL
)
INSERT #emp ([id], [name], [mgrid]) VALUES (1, N'a', 0)
INSERT #emp ([id], [name], [mgrid]) VALUES (2, N'a1', 1)
INSERT #emp ([id], [name], [mgrid]) VALUES (3, N'a11', 2)
INSERT #emp ([id], [name], [mgrid]) VALUES (4, N'a12', 2)
INSERT #emp ([id], [name], [mgrid]) VALUES (5, N'a13', 2)
INSERT #emp ([id], [name], [mgrid]) VALUES (6, N'a2', 1)
INSERT #emp ([id], [name], [mgrid]) VALUES (7, N'a3', 1)
INSERT #emp ([id], [name], [mgrid]) VALUES (8, N'a31', 7)
INSERT #emp ([id], [name], [mgrid]) VALUES (9, N'a32', 7)
INSERT #emp ([id], [name], [mgrid]) VALUES (10, N'b', 0)
INSERT #emp ([id], [name], [mgrid]) VALUES (11, N'b1', 10)
INSERT #emp ([id], [name], [mgrid]) VALUES (12, N'b2', 10);
with cte (id,name, MGRID) as
(
select id, name,MGRID
from #emp
union all
select c.id, c.name, c.MGRID
from #emp c
inner join cte p
on c.mgrid = P.id
)
SELECT Distinct * FROM CTE
WITH RCTE AS
(
SELECT id, name, mgrid, CAST('' AS NVARCHAR(MAX)) AS blanks , CAST(name AS NVARCHAR(MAX)) AS ordr
FROM dbo.emp WHERE mgrid = 0
UNION ALL
SELECT e.id, e.name, e.mgrid, blanks + ' ' AS blanks, ordr + e.name AS ordr
FROM dbo.emp e
INNER JOIN RCTE r ON e.mgrid = r.id
)
SELECT blanks + name FROM RCTE
ORDER BY ordr

Add not relevant column to group by script

This is my sample table and values:
CREATE TABLE [dbo].[Test]
(
[Id] BIGINT NOT NULL DEFAULT(0),
[VId] BIGINT NOT NULL DEFAULT(0),
[Level] INT NOT NULL DEFAULT(0)
);
INSERT INTO [dbo].[Test] ([Id], [VId], [Level]) VALUES (100, 1, 1);
INSERT INTO [dbo].[Test] ([Id], [VId], [Level]) VALUES (101, 1, 2);
INSERT INTO [dbo].[Test] ([Id], [VId], [Level]) VALUES (102, 1, 3);
INSERT INTO [dbo].[Test] ([Id], [VId], [Level]) VALUES (103, 2, 1);
INSERT INTO [dbo].[Test] ([Id], [VId], [Level]) VALUES (104, 3, 1);
INSERT INTO [dbo].[Test] ([Id], [VId], [Level]) VALUES (105, 3, 2);
INSERT INTO [dbo].[Test] ([Id], [VId], [Level]) VALUES (106, 4, 1);
INSERT INTO [dbo].[Test] ([Id], [VId], [Level]) VALUES (107, 4, 2);
INSERT INTO [dbo].[Test] ([Id], [VId], [Level]) VALUES (108, 4, 3);
INSERT INTO [dbo].[Test] ([Id], [VId], [Level]) VALUES (109, 4, 4);
So at now I use this script:
SELECT
[T].[VId], MAX ([T].[Level]) AS [MaxLevel]
FROM
[dbo].[Test] AS [T]
GROUP BY
[T].[VId];
And it returns:
VId MaxLevel
1 3
2 1
3 2
4 4
But I need Id column also and I can't add it to Group by script, I need the following values:
VId MaxLevel Id
1 3 102
2 1 103
3 2 105
4 4 109
What is your suggestion?
Also The following values is enough The Id's With Max(Level) in any VId :
Id
102
103
105
109
A 2008 take on the question, since that's what you're working with:
declare #Test table
(
[Id] BIGINT NOT NULL DEFAULT(0),
[VId] BIGINT NOT NULL DEFAULT(0),
[Level] INT NOT NULL DEFAULT(0)
);
INSERT INTO #Test ([Id], [VId], [Level])
VALUES (100, 1, 1),(101, 1, 2),(102, 1, 3),(103, 2, 1),(104, 3, 1),
(105, 3, 2),(106, 4, 1),(107, 4, 2),(108, 4, 3),(109, 4, 4);
;With Numbered as (
select *,
RANK() OVER (PARTITION BY VId ORDER BY [Level] desc) as rn
from #Test)
select VId,Level,Id from Numbered where rn=1
Note that (as with the other solutions) this will output multiple rows per VId if there are two rows with the same maximum level. If you don't want that, switch RANK() to ROW_NUMBER() and an arbitrary one will win - or if you want a specific winner in the case of a tie, add that condition into the ORDER BY of the window function.
Use joining with the same table by VId column
something like this:
SELECT [T].[VId], [T].[MaxLevel], [T1].[Id]
FROM [dbo].[Test] AS [T1] JOIN
(SELECT [T].[VId], MAX ([T].[Level]) AS [MaxLevel]
FROM [dbo].[Test] AS [T]
GROUP BY [T].[VId]) AS [T]
ON [T1].[VId] = [T].[VId]
AND [T1].[Level] = [T].[MaxLevel]
ORDER BY [T].[VId];
the result will be:
VId MaxLevel Id
1 3 102
2 1 103
3 2 105
4 4 109
Use this:
WITH LastLevels AS
(
SELECT
[T].[VId] AS [VID],
MAX ([T].[Level]) AS [MaxLevel]
FROM [dbo].[Test] AS [T]
GROUP BY [T].[VId]
)
SELECT [LastLevels].[VID],[LastLevels].[MaxLevel], [Te].[Id]
FROM [dbo].[Test] AS [Te]
INNER JOIN [LastLevels]
ON [LastLevels].[VID]=[Te].[VId]
AND [LastLevels].[MaxLevel]=[Te].[Level]
ORDER BY [LastLevels].[VID];
SELECT ID, [VId], [MaxLevel] From
(
SELECT
[T].[VId], MAX ([T].[Level]) AS [MaxLevel]
FROM
[dbo].[Test] AS [T]
GROUP BY
[T].[VId]
)K
INNER JOIN [Test] T on T.[VId] = K.[VId] and T.[Level] = K.MaxLevel