Related
I am trying to get the statement on fetching the previous and next rows of a selected row.
Declare #OderDetail table
(
Id int primary key,
OrderId int,
ItemId int,
OrderDate DateTime2,
Lookup varchar(15)
)
INSERT INTO #OderDetail
VALUES
(1, 10, 1, '2018-06-11', 'A'),
(2, 10, 2, '2018-06-11', 'BE'), --this
(3, 2, 1, '2018-06-04', 'DR'),
(4, 2, 2, '2018-06-04', 'D'), --this
(5, 3, 2, '2018-06-14', 'DD'), --this
(6, 4, 2, '2018-06-14', 'R');
DECLARE
#ItemId int = 2,
#orderid int = 10
Required output:
Input for the procedure is order id =10 and item id =2 and i need to check item-2 is in the any other order i.e only previous and next item of matched record/order as per order date
Is this what your after? (Updated to reflect edit [OrderDate] to question)
Declare #OderDetail table
(
Id int primary key,
OrderId int,
ItemId int,
OrderDate DateTime2,
Lookup varchar(15)
)
INSERT INTO #OderDetail
VALUES
(1, 10, 1, '2018-06-11', 'A'),
(2, 10, 2, '2018-06-11', 'BE'), --this
(3, 2, 1, '2018-06-04', 'DR'),
(4, 2, 2, '2018-06-04', 'D'), --this
(5, 3, 2, '2018-06-14', 'DD'), --this
(6, 4, 2, '2018-06-14', 'R');
declare #ItemId int=2 , #orderid int = 10;
Query
With cte As
(
Select ROW_NUMBER() OVER(ORDER BY OrderDate) AS RecN,
*
From #OderDetail Where ItemId=#ItemId
)
Select Id, OrderId, ItemId, [Lookup] From cte Where
RecN Between ((Select Top 1 RecN From cte Where OrderId = #orderid) -1) And
((Select Top 1 RecN From cte Where OrderId = #orderid) +1)
Order by id
Result:
Id OrderId ItemId Lookup
2 10 2 BE
4 2 2 D
5 3 2 DD
Another possible approach is to use LAG() and LEAD() functions, that return data from a previous and subsequent row form the same resul tset.
-- Table
DECLARE #OrderDetail TABLE (
Id int primary key,
OrderId int,
ItemId int,
OrderDate DateTime2,
Lookup varchar(15)
)
INSERT INTO #OrderDetail
VALUES
(1, 10, 1, '2018-06-11', 'A'),
(2, 10, 2, '2018-06-11', 'BE'), --this
(3, 2, 1, '2018-06-04', 'DR'),
(4, 2, 2, '2018-06-04', 'D'), --this
(5, 3, 2, '2018-06-14', 'DD'), --this
(6, 4, 2, '2018-06-14', 'R');
-- Item and order
DECLARE
#ItemId int = 2,
#orderid int = 10
-- Statement
-- Get previois and next ID for every order, grouped by ItemId, ordered by OrderDate
;WITH cte AS (
SELECT
Id,
LAG(Id, 1) OVER (PARTITION BY ItemId ORDER BY OrderDate) previousId,
LEAD(Id, 1) OVER (PARTITION BY ItemId ORDER BY OrderDate) nextId,
ItemId,
OrderId,
Lookup
FROM #OrderDetail
)
-- Select current, previous and next order
SELECT od.*
FROM cte
CROSS APPLY (SELECT * FROM #OrderDetail WHERE Id = cte.Id) od
WHERE (cte.OrderId = #orderId) AND (cte.ItemId = #ItemId)
UNION ALL
SELECT od.*
FROM cte
CROSS APPLY (SELECT * FROM #OrderDetail WHERE Id = cte.previousId) od
WHERE (cte.OrderId = #orderId) AND (cte.ItemId = #ItemId)
UNION ALL
SELECT od.*
FROM cte
CROSS APPLY (SELECT * FROM #OrderDetail WHERE Id = cte.nextId) od
WHERE (cte.OrderId = #orderId) AND (cte.ItemId = #ItemId)
Output:
Id OrderId ItemId OrderDate Lookup
2 10 2 11/06/2018 00:00:00 BE
4 2 2 04/06/2018 00:00:00 D
5 3 2 14/06/2018 00:00:00 DD
Update to given this data set: I see where you are going with this. Note that in SOME cases there IS no row before the given one - so it only returns 2 not 3. Here I updated the CTE version. Un-comment the OTHER row to see 3 not 2 as there is then one before the selected row with that Itemid.
Added a variable to demonstrate how this is better allowing you to get 1 before and after or 2 before/after if you change that number (i.e. pass a parameter) - and if less rows, or none are before or after it gets as many as it can within that constraint.
Data setup for all versions:
Declare #OderDetail table
(
Id int primary key,
OrderId int,
ItemId int,
OrderDate DateTime2,
Lookup varchar(15)
)
INSERT INTO #OderDetail
VALUES
(1, 10, 1, '2018-06-11', 'A'),
(2, 10, 2, '2018-06-11', 'BE'), --this
(3, 2, 1, '2018-06-04', 'DR'),
(4, 2, 2, '2018-06-04', 'D'), --this
(5, 3, 2, '2018-06-14', 'DD'), --this
(9, 4, 2, '2018-06-14', 'DD'),
(6, 4, 2, '2018-06-14', 'R'),
--(10, 10, 2, '2018-06-02', 'BE'), -- un-comment to see one before
(23, 4, 2, '2018-06-14', 'R');
DECLARE
#ItemId int = 2,
#orderid int = 2;
CTE updated version:
DECLARE #rowsBeforeAndAfter INT = 1;
;WITH cte AS (
SELECT
Id,
OrderId,
ItemId,
OrderDate,
[Lookup],
ROW_NUMBER() OVER (ORDER BY OrderDate,Id) AS RowNumber
FROM #OderDetail
WHERE
ItemId = #itemId -- all matches of this
),
myrow AS (
SELECT TOP 1
Id,
OrderId,
ItemId,
OrderDate,
[Lookup],
RowNumber
FROM cte
WHERE
ItemId = #itemId
AND OrderId = #orderid
)
SELECT
cte.Id,
cte.OrderId,
cte.ItemId,
cte.OrderDate,
cte.[Lookup],
cte.RowNumber
FROM ctE
INNER JOIN myrow
ON ABS(cte.RowNumber - myrow.RowNumber) <= #rowsBeforeAndAfter
ORDER BY OrderDate, OrderId;
You probably want the CTE method (See an original at the end of this) however:
Just to point out, this gets the proper results but is probably not what you are striving for since it is dependent on the row order and the item id not the actual row with those two values:
SELECT TOP 3
a.Id,
a.OrderId,
a.ItemId,
a.Lookup
FROM #OderDetail AS a
WHERE
a.ItemId = #ItemId
To fix that, you can use an ORDER BY and TOP 1 with a UNION, kind of ugly. (UPDATED with date sort and != on the id.)
SELECT
u.Id,
u.OrderId,
u.OrderDate,
u.ItemId,
u.Lookup
FROM (
SELECT
a.Id,
a.OrderId,
a.OrderDate,
a.ItemId,
a.Lookup
FROM #OderDetail AS a
WHERE
a.ItemId = #ItemId
AND a.OrderId = #orderid
UNION
SELECT top 1
b.Id,
b.OrderId,
b.OrderDate,
b.ItemId,
b.Lookup
FROM #OderDetail AS b
WHERE
b.ItemId = #ItemId
AND b.OrderId != #orderid
ORDER BY b.OrderDate desc, b.OrderId
UNION
SELECT top 1
b.Id,
b.OrderId,
b.OrderDate,
b.ItemId,
b.Lookup
FROM #OderDetail AS b
WHERE
b.ItemId = #ItemId
AND b.OrderId != #orderid
ORDER BY b.OrderDate asc, b.OrderId
) AS u
ORDER BY u.OrderDate asc, u.OrderId
I think its simple, you can check with min(Id) and Max(id) with left outer join or outer apply
like
Declare #ItemID int = 2
Select * From #OderDetail A
Outer Apply (
Select MIN(A2.Id) minID, MAX(A2.Id) maxID From #OderDetail A2
Where A2.ItemId =#ItemID
) I05
Outer Apply(
Select * From #OderDetail Where Id=minID-1
Union All
Select * From #OderDetail Where Id=maxID+1
) I052
Where A.ItemId =#ItemID Order By A.Id
Let me know if this helps you or you face any problem with it...
Regards,
I have a simple categories table as with the following columns:
Id
Name
ParentId
So, an infinite amount of Categories can be the child of a category. Take for example the following hierarchy:
I want, in a simple query that returns the category "Business Laptops" to also return a column with all it's parents, comma separator or something:
Or take the following example:
Recursive cte to the rescue....
Create and populate sample table (Please save us this step in your future questions):
DECLARE #T as table
(
id int,
name varchar(100),
parent_id int
)
INSERT INTO #T VALUES
(1, 'A', NULL),
(2, 'A.1', 1),
(3, 'A.2', 1),
(4, 'A.1.1', 2),
(5, 'B', NULL),
(6, 'B.1', 5),
(7, 'B.1.1', 6),
(8, 'B.2', 5),
(9, 'A.1.1.1', 4),
(10, 'A.1.1.2', 4)
The cte:
;WITH CTE AS
(
SELECT id, name, name as path, parent_id
FROM #T
WHERE parent_id IS NULL
UNION ALL
SELECT t.id, t.name, cast(cte.path +','+ t.name as varchar(100)), t.parent_id
FROM #T t
INNER JOIN CTE ON t.parent_id = CTE.id
)
The query:
SELECT id, name, path
FROM CTE
Results:
id name path
1 A A
5 B B
6 B.1 B,B.1
8 B.2 B,B.2
7 B.1.1 B,B.1,B.1.1
2 A.1 A,A.1
3 A.2 A,A.2
4 A.1.1 A,A.1,A.1.1
9 A.1.1.1 A,A.1,A.1.1,A.1.1.1
10 A.1.1.2 A,A.1,A.1.1,A.1.1.2
See online demo on rextester
I have a chart like picture , that store it in table with KID , ParentID .
how can i get max MR for all child under parent.
example : for Node C ----> max ( MR(D) , MR(E) , MR(F) )
How can find Max(MR) for all child of node?
DECLARE #a TABLE
(
KID INT PRIMARY KEY,
ParentID INT,
MR INT
)
INSERT INTO #a (KID, ParentID, MR)
VALUES
(1, 0, 3), (2, 1, 1), (3, 1, 3),
(4, 3, 3), (5, 3, 5), (6, 5, 3)
;WITH cte AS
(
SELECT *
FROM #a
WHERE ParentID = 3
UNION ALL
SELECT t2.*
FROM cte t1
JOIN #a t2 ON t1.ParentID = t2.KID
)
SELECT MAX(MR)
FROM cte
OPTION (MAXRECURSION 0)
result -
5
Maybe you can use over clause
SELECT
ParentID,
MAX(MR) OVER(PARTITION BY ParentID)
FROM
Table
I am using SQL Server 2008.In my databse one table like:
------------------------------
id parentId name
------------------------------
1 NULL india
2 1 gujrat
3 1 Maharastra
4 1 rajsthan
5 2 ahmedabad
6 2 rajkot
7 NULL USA
8 7 newyork
1 3 mumbai
1 3 goa
1 4 jaipur
1 7 californiya
Here i want to get this data with it's level in hierarchy, so i create query like:
with RecursiveTable_CTE (Id,Parentid,Name_cte,Hlevel)
as
(
select id , parentId, name, 0 as Hlevel from treeTable where id = 1
union all
select t.id,t.parentId,t.name, Hlevel + 1 as LEVEL from treeTable as t inner join RecursiveTable_CTE as rtc on t.id = rtc.Parentid
)
select * from RecursiveTable_CTE option (maxrecursion 0)
and also try
with RecursiveTable_CTE (Id,Parentid,Name_cte,Hlevel)
as
(
select id , parentId, name, 0 as Hlevel from treeTable where parentId is null
union all
select t.id,t.parentId,t.name, Hlevel + 1 as LEVEL from treeTable as t inner join RecursiveTable_CTE as rtc on rtc.id = t.parentId
)
select * from RecursiveTable_CTE option (maxrecursion 0)
but both result infinite loop.
can any one help me?
I think the query you're after is this:
with RecursiveTable_CTE (Id,Parentid,Name_cte,Hlevel)
as
(
select id , parentId, name, 0 as Hlevel
from treeTable
where parentId is null
union all
select t.id,t.parentId,t.name, rtc.Hlevel + 1 as Hlevel
from treeTable as t
inner join RecursiveTable_CTE as rtc on t.Parentid = rtc.id
)
select * from RecursiveTable_CTE
The problem is though that I think your data is not correct and id and parentId are swapped in some rows. I used this data:
insert into treeTable values (1, NULL, 'india')
insert into treeTable values (2, 1, 'gujrat')
insert into treeTable values (3, 1, 'Maharastra')
insert into treeTable values (4, 1, 'rajsthan')
insert into treeTable values (5, 2, 'ahmedabad')
insert into treeTable values (6, 2, 'rajkot')
insert into treeTable values (7, NULL, 'USA')
insert into treeTable values (8, 7 , 'newyork')
insert into treeTable values (9, 1 , 'mumbai')
insert into treeTable values (10, 1 , 'goa')
insert into treeTable values (11, 1 , 'jaipur')
insert into treeTable values (12, 7 , 'californiya')
SQL Fiddle demo
Here in your case ther 1 is top level but again 1 has parents 3,4,7.
your infinite loop is due to your wrong herarchy.
id parentId name
------------------------------
1 NULL india
1 3 mumbai
1 4 jaipur
1 7 californiya
You have duplicates in the ID column, Is that a typo? If you don't have duplicates
CREATE TABLE states
(
[id] INT,[parentid] INT,[name] VARCHAR(11)
);
INSERT INTO states
([id],[parentid],[name])
VALUES (1,NULL,'india'),
(2,1,'gujrat'),
(3,1,'Maharastra'),
(4,1,'rajsthan'),
(5,2,'ahmedabad'),
(6,2,'rajkot'),
(7,NULL,'USA'),
(8,7,'newyork'),
(9,3,'mumbai'),
(10,3,'goa'),
(11,4,'jaipur'),
(12,7,'californiya');
WITH recursivetable_cte (id, parentid, name_cte, hlevel)
AS (SELECT id,parentid,name,0 AS Hlevel
FROM states
WHERE parentid IS NULL
UNION ALL
SELECT t.id,t.parentid,t.name,hlevel + 1 AS LEVEL
FROM states AS t
INNER JOIN recursivetable_cte AS rtc
ON t.parentid = rtc.id)
SELECT *
FROM recursivetable_cte
OPTION (maxrecursion 0)
#Szymom is right.id should be unique.though in this query no need of changing table data
see the change,
;with RecursiveTable_CTE (Id,Parentid,Name_cte,Hlevel)
as
(
select id , parentId, name, 0 as Hlevel from #t where id = 1 **and parentId is null**
union all
select t.id,t.parentId,t.name, Hlevel+ 1 as LEVEL from #t as t
inner join RecursiveTable_CTE as rtc on t.Parentid = rtc.id **and t.id<>1**
)
select * from RecursiveTable_CTE
I have simple SQL Server query:
declare #table table (id int, name nvarchar(5), deleted bit)
insert into #table(id, name, deleted) values(1, 'A1', 0)
insert into #table(id, name, deleted) values(2, 'A1', 0)
insert into #table(id, name, deleted) values(3, 'A1', 0)
insert into #table(id, name, deleted) values(4, 'A1', 1)
insert into #table(id, name, deleted) values(5, 'A2', 0)
insert into #table(id, name, deleted) values(6, 'A2', 0)
select
max(id) as id,
name
from #table
where deleted = 0
group by name
it returns to rows
id |name
--------------
3 |A1
6 |A2
but should return only one
id |name
--------------
6 |A2
since last (or max) id of A1 is deleted.
How to fix my query.
Thanks a lot.
Since you could have a third set like this:
insert into #table(id, name, deleted) values(7, 'A3', 1)
insert into #table(id, name, deleted) values(8, 'A3', 0)
I assume you want the following returned as well, since the highest id for that name was not marked as deleted:
id name
---- ----
8 A3
Then this query should do it:
;WITH x AS
(
SELECT id, name, deleted,
rn = ROW_NUMBER() OVER (PARTITION BY name ORDER BY id DESC)
FROM #table
)
SELECT id = MAX(id), name
FROM x
WHERE NOT EXISTS
(
SELECT 1 FROM x AS x2
WHERE name = x.name
AND deleted = 1 AND rn = 1
)
GROUP BY name;
If you only want rows returned where no row for a particular name was ever deleted, then it's slightly simpler:
SELECT id = MAX(id), name
FROM #table AS t
WHERE NOT EXISTS
(
SELECT 1 FROM #table
WHERE name = t.name AND deleted = 1
)
GROUP BY name;
Another approach: http://www.sqlfiddle.com/#!3/697d7/5
create table t(id int, name nvarchar(5), deleted bit)
insert into t(id, name, deleted) values(1, 'A1', 0)
insert into t(id, name, deleted) values(2, 'A1', 0)
insert into t(id, name, deleted) values(3, 'A1', 0)
insert into t(id, name, deleted) values(4, 'A1', 1)
insert into t(id, name, deleted) values(5, 'A2', 0)
insert into t(id, name, deleted) values(6, 'A2', 0)
with no_deletions as
(
select name
from t
group by name
having max(nullif(cast(deleted as int),0)) is null
)
select
max(id) as id,
name
from t
where name in (select name from no_deletions)
group by name
Output:
| ID | NAME |
-------------
| 6 | A2 |