I have a situation which I need to do pagination along with INNET JOIN. Here is a similar scenario I have:
DECLARE #categories AS TABLE(
CatID INT,
CategoryName NVARCHAR(100)
);
DECLARE #fooTable AS TABLE(
ID INT,
CatID INT,
Name NVARCHAR(100),
MinAllow INT,
Price DECIMAL(18,2)
);
INSERT INTO #categories VALUES(1, 'Cat1');
INSERT INTO #categories VALUES(2, 'Cat2');
INSERT INTO #categories VALUES(3, 'Cat3');
INSERT INTO #categories VALUES(4, 'Cat4');
INSERT INTO #categories VALUES(5, 'Cat5');
INSERT INTO #fooTable VALUES(1, 1, 'Product1', 2, 112.2);
INSERT INTO #fooTable VALUES(3, 1, 'Product3', 5, 233.32);
INSERT INTO #fooTable VALUES(6, 1, 'Product6', 4, 12.43);
INSERT INTO #fooTable VALUES(7, 4, 'Product7', 4, 12.43);
INSERT INTO #fooTable VALUES(8, 5, 'Product8', 4, 12.43);
These are the records I have. As you can see, some categories do not have any products inside #fooTable. As a next step, we have the following SELECT statement:
SELECT * FROM #fooTable ft
INNER JOIN (
SELECT ROW_NUMBER() OVER (ORDER BY CatID) AS RowNum, * FROM #categories
) AS cat ON (cat.CatID = ft.CatID);
It is a basic JOIN except that the output will also carry the row number of the categories. The result I got for this query is as follows:
ID CatID Name MinAllow Price RowNum CatID CategoryName
---- ------- ------------- ----------- --------- -------- -------- -------------
1 1 Product1 2 112.20 1 1 Cat1
3 1 Product3 5 233.32 1 1 Cat1
6 1 Product6 4 12.43 1 1 Cat1
7 4 Product7 4 12.43 4 4 Cat4
8 5 Product8 4 12.43 5 5 Cat5
When you look at the RowNum column, you will see that those values are not pagination friendly. So, when I try to paginate this table as follows, I got an incorrect output:
SELECT * FROM #fooTable ft
INNER JOIN (
SELECT ROW_NUMBER() OVER (ORDER BY CatID) AS RowNum, * FROM #categories
)AS cat ON (cat.CatID = ft.CatID) AND (cat.RowNum BETWEEN 1 AND 2);
The real situation I have is similar to this one but that query is so complicated and I need to get it working with INNER JOIN. I hope I made it clear. Any idea how I got something like that working?
Edit
According to the above result of my first select query, I should be able to retrieve products whose CatID is 1 and 4 on my second query. That's what I aim.
One solution can be the next one:
SELECT x.*
FROM
(
SELECT ft.*,
cat.CategoryName,
DENSE_RANK() OVER (ORDER BY ft.CatID) AS Rnk
FROM #fooTable ft
INNER JOIN #categories cat ON (cat.CatID = ft.CatID)
) AS x
WHERE x.Rnk BETWEEN 1 AND 2
Results:
ID CatID Name MinAllow Price CategoryName Rnk
-- ----- -------- -------- ------- ------------ ---
1 1 Product1 2 112.20 Cat1 1
3 1 Product3 5 233.32 Cat1 1
6 1 Product6 4 12.43 Cat1 1
7 4 Product7 4 12.43 Cat4 2
Related
I have two tables ,
Table 1
Id Name
===========
1 Name1
2 Name2
3 Name3
Table 2
Id Tb1Id DateTime
=======================
1 1 20-09-2017
2 1 01-09-2018
3 2 01-09-2016
4 2 02-09-2015
5 3 06-09-2016
6 3 10-09-2019
I want to join those two tables by where Table1.Id = Table2.Tb1Id and get the maximum datetime value from Table2. The result should be like this .
Id Name DateTime
========================
1 Name1 01-09-2018
2 Name2 01-09-2016
3 Name3 10-09-2019
Try This
DECLARE #Table1 AS TABLE(Id INT,Name VARCHAR(20))
INSERT INTO #Table1
SELECT 1,'Name1' UNION ALL
SELECT 2,'Name2' UNION ALL
SELECT 3,'Name3'
DECLARE #Table2 AS TABLE(Id INT, Tb1Id INT,[DateTime] DATETIME)
INSERT INTO #Table2
SELECT 1,1,'2017-09-20' UNION ALL
SELECT 2,1,'2018-09-01' UNION ALL
SELECT 3,2,'2016-09-01' UNION ALL
SELECT 4,2,'2015-09-02' UNION ALL
SELECT 5,3,'2016-09-06' UNION ALL
SELECT 6,3,'2019-09-10'
SELECT t2.Tb1Id AS Id,
t1.Name,
MAX(t2.[DateTime]) AS [DateTime]
FROM #Table1 AS T1
INNER JOIN #Table2 AS t2
ON T1.Id = t2.Tb1Id
GROUP BY
t2.Tb1Id,
t1.Name
Result
Id Name DateTime
-----------------------------------
1 Name1 2018-09-01 00:00:00.000
2 Name2 2016-09-01 00:00:00.000
3 Name3 2019-09-10 00:00:00.000
Good morning all
I would appreciate any help you can give me in this subject
I have a table that grows in time with the same Id1
but some time Id2 change , like a historic of a park.
I would like to find the best way with a query to retrieve
the rows where id2 changes and time
example if table contents are
Id1 Id2 time
1 1 10:00
1 1 10:30
1 2 10:40
1 2 10:45
1 2 11:00
1 3 11:45
1 3 12:45
query output would be
Id1 oldId2 newId2 time
1 1 2 10:40
1 2 3 11:45
i have done with a stored procedure, but I was wondering of there is a faster/cleaner way to get this
thanks in advance
You can do this by Ranking functions..
Schema:
CREATE TABLE #TAB (Id1 INT,Id2 INT, timeS TIME )
INSERT INTO #TAB
SELECT 1 AS Id1 , 1 Id2, '10:00' AS timeS
UNION ALL
SELECT 1, 1, '10:30'
UNION ALL
SELECT 1, 2, '10:40'
UNION ALL
SELECT 1, 2, '10:45'
UNION ALL
SELECT 1, 2, '11:00'
UNION ALL
SELECT 1, 3, '11:45'
UNION ALL
SELECT 1, 3, '12:45'
Now do select with ROW_NUMBER and CTE for retrieving previous/next row values.
;WITH CTE
AS (
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS RNO
,ID1
,ID2
,timeS
FROM (
SELECT ROW_NUMBER() OVER (PARTITION BY ID2 ORDER BY TIMES) AS SNO
,*
FROM #TAB
) A
WHERE SNO = 1
)
SELECT C1.Id1
,C1.Id2 AS OLD_ID2
,C2.Id2 AS NEW_ID2
,C2.timeS
FROM CTE C1
LEFT JOIN CTE C2 ON C1.RNO + 1 = C2.RNO
WHERE C2.Id1 IS NOT NULL
Result:
+-----+---------+---------+------------------+
| Id1 | OLD_ID2 | NEW_ID2 | timeS |
+-----+---------+---------+------------------+
| 1 | 1 | 2 | 10:40:00.0000000 |
| 1 | 2 | 3 | 11:45:00.0000000 |
+-----+---------+---------+------------------+
Note: If you want to get Previous/Next Row values into current row, you can use LEAD LAG functions. But they support only in SQL Server 2012+.
The above Left Join with CTE will work for lower versions too.
declare #t table (Id1 int, Id2 int, [time] time)
insert into #t
select 1, 1, '10:00' union
select 1, 1, '10:30' union
select 1, 2, '10:40' union
select 1, 2, '10:45' union
select 1, 2, '11:00' union
select 1, 3, '11:45' union
select 1, 3, '12:45'
select Id1, oldId = (select top 1 id2 from #t where Id1=t.Id1 and Id2 < t.Id2 order by id2, time desc), newId = id2, time = min(time)
from #t t
where id2 > 1
group by Id1, id2
i have done some changes to the code from Shakeer Mirza.
the pratical problem that originated the question in the first place is:
i have a table that represents the history of an equipment. Being machine internal id(Num_TPA).
Each time there is a malfunction, the machine is replaced by another it keeps the same Num_TPA but Serial_number changes
i needed to know what is the historic on internal_id->Num_TPA . the new and the old serial_number , and the date of replacement
and this is what it came out.
;WITH CTE
AS (
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS RNO
,[Num_TPA]
,[Serial_number]
,[Time]
,a.SNO
FROM (
SELECT ROW_NUMBER() OVER (PARTITION BY [Num_TPA]
ORDER BY [Data_Hora_Ficheiro]) AS SNO
,*
FROM tab_values
) A
WHERE SNO > 1
)
SELECT C1.[Num_TPA]
,C1.[Serial_number] AS OLD_ID2
,C2.[Serial_number] AS NEW_ID2
,C2.[Data_Hora_Ficheiro]
,c2.SNO
,c2.RNO
FROM tab_values C1
LEFT JOIN CTE C2 ON (
C1.[Num_TPA] = C2.[Num_TPA]
AND c1.[Serial_number] != c2.[Serial_number]
AND C2.[Time] > c1.TIME
)
WHERE C2.[Num_TPA] IS NOT NULL
AND SNO = 2
UNION
SELECT C1.[Num_TPA]
,C1.[Serial_number] AS OLD_ID2
,C2.[Serial_number] AS NEW_ID2
,C2.[Data_Hora_Ficheiro]
,c2.SNO
,c2.RNO
FROM CTE C1
LEFT JOIN CTE C2 ON (
C1.SNO + 1 = C2.SNO
AND C1.[Num_TPA] = C2.[Num_TPA]
)
WHERE C2.[Num_TPA] IS NOT NULL
AND C2.SNO > 2
Brothers can you help me? Thanks
Table A
Id Name IdParent
1 Operation Null
2 Developer 1
3 Android 2
4 IOS 2
Expectes result:
ID Name
1 +Operation
2 +------ Developer
3 +------------Android
4 +------------ IOS
By adding a sequence during the recursive build, you can easily create the proper presentation sequence and nesting
Declare #YourTable table (id int,IdParent int,Name varchar(50))
Insert into #YourTable values
( 1, NULL,'Operation')
,( 2, 1 ,'Developer')
,( 3, 2 ,'Android')
,( 4, 2 ,'IOS')
,( 5, 1 ,'Poet')
,( 6, 5 ,'Limerick')
,( 7, 5 ,'Haiku')
Declare #Top int = null --<< Sets top of Hier Try 2
Declare #Nest varchar(25) = '|-----' --<< Optional: Added for readability
;with cteP as (
Select Seq = cast(10000+Row_Number() over (Order by Name) as varchar(500))
,ID
,IdParent
,Lvl=1
,Name
From #YourTable
Where IsNull(#Top,-1) = case when #Top is null then isnull(IdParent ,-1) else ID end
Union All
Select Seq = cast(concat(p.Seq,'.',10000+Row_Number() over (Order by r.Name)) as varchar(500))
,r.ID
,r.IdParent
,p.Lvl+1
,r.Name
From #YourTable r
Join cteP p on r.IdParent = p.ID)
Select A.ID
,A.IdParent
,A.Lvl
,Name = Replicate(#Nest,A.Lvl-1) + A.Name
From ctep A
Order By A.Seq
Returns
ID IdParent Lvl Name
1 NULL 1 Operation
2 1 2 |-----Developer
3 2 3 |-----|-----Android
4 2 3 |-----|-----IOS
5 1 2 |-----Poet
7 5 3 |-----|-----Haiku
6 5 3 |-----|-----Limerick
Here's another version:
WITH RawData AS (
SELECT 1 AS Id, 'Operation' AS Name, CONVERT(INT, NULL) AS IdParent
UNION ALL
SELECT 2 AS Id, 'Developer' AS Name, 1 AS IdParent
UNION ALL
SELECT 3 AS Id, 'Android' AS Name, 2 AS IdParent
UNION ALL
SELECT 4 AS Id, 'IOS' AS Name, 2 AS IdParent),
Depth AS (
SELECT
Id,
1 AS depth,
IdParent
FROM
RawData
UNION ALL
SELECT
d.Id,
d.depth + 1,
r.IdParent
FROM
Depth d
INNER JOIN RawData r ON r.Id = d.IdParent),
MaxDepth AS (
SELECT
Id,
MAX(depth) AS depth
FROM
Depth
GROUP BY
Id)
SELECT
r.Id,
'+' + REPLICATE('----', m.depth - 1) + r.Name AS Name
FROM
RawData r
INNER JOIN MaxDepth m ON m.Id = r.Id;
Results:
Id Name
1 +Operation
2 +----Developer
3 +--------Android
4 +--------IOS
DECLARE #mockup TABLE(Id INT, Name VARCHAR(100), IdParent INT);
INSERT INTO #mockup VALUES
(1,'Operation',Null)
,(2,'Developer',1)
,(3,'Android',2)
,(4,'IOS',2);
--The query uses a recursive CTE and finally REPLICATE with the recursive level to add the number of hyphens...
WITH recCTE AS
(
SELECT Id, Name, 1 AS Lvl, CAST(REPLACE(STR(ROW_NUMBER() OVER (ORDER BY Id),5),' ','0') AS VARCHAR(MAX)) AS Seq
FROM #mockup
WHERE IdParent IS NULL
UNION ALL
SELECT m.Id,m.Name,r.Lvl +1,r.Seq + '.' + REPLACE(STR(ROW_NUMBER() OVER (ORDER BY m.Id),5),' ','0')
FROM #mockup AS m
INNER JOIN recCTE AS r ON m.IdParent=r.Id
)
SELECT *
,'+' + REPLICATE('-',Lvl*4) + Name
FROM recCTE
ORDER BY Seq
the result
+----+-----------+-----+----------------------+
| Id | Name | Lvl | (Kein Spaltenname) |
+----+-----------+-----+----------------------+
| 1 | Operation | 1 | +----Operation |
+----+-----------+-----+----------------------+
| 2 | Developer | 2 | +--------Developer |
+----+-----------+-----+----------------------+
| 3 | Android | 3 | +------------Android |
+----+-----------+-----+----------------------+
| 4 | IOS | 3 | +------------IOS |
+----+-----------+-----+----------------------+
I have a table that contains id, type.
I want to select all the ids that have only one or more records of the same type.
For example,
Assuming this is my table:
id type
456 4
123 4
123 4
123 18
123 4
789 4
789 4
000 7
I want to get ids: 456,789 cause those ids have only records with type = 4:
456 has one record, and 789 has two records of type = 4.
123 has type = 4, but has type = 18.
How can I do it?
I know I can use partition, but I want something like join/exists..
http://sqlfiddle.com/#!9/731e1
You can use:
SELECT id
FROM cards
GROUP BY id
HAVING MIN(type) = MAX(type)
Demo here
Select Id
FROM cards
GROUP BY Id
HAVING COUNT(DISTINCT [type]) = 1
I don't think #M.Ali answer mets your critera. His resultset includes id = '000'
if OBJECT_ID('Tempdb..#Work') is not null
drop table #Work;
Create Table #Work (Id char(3), [Type] int)
insert into #Work values
( '456', 4)
, ('123', 4)
, ('123', 4)
, ('123', 18)
, ('123', 4)
, ('789', 4)
, ('789', 4)
, ('000', 7)
select distinct *
from #Work a
where exists (
select Type
,Count(Distinct Id) cntId
from #Work b
where a.Type = b.Type
group by Type
having Count(Distinct Id) > 1
)
and exists (
select Id
,count(distinct Type)
from #Work c
where a.Id = c.Id
group by id
having count(distinct type)= 1
)
output:
Id Type
---- -----------
456 4
789 4
here is the link of the picture:
help i need to create something like table 3..
i already have a query that has them all except for the count2 column, i don't know how to create that in query..
here's my code in query:
SELECT a.rn,'',a.id, b.iddesc
INTO #x
FROM (
SELECT ROW_NUMBER() OVER (ORDER BY [desc]) AS rn, *
FROM aa
) a, bb AS b
WHERE b.idcon = a.id
SELECT *
FROM #x
sorry i don't know how to explain it well,
Try this one -
Query:
DECLARE #table_a TABLE (id INT, [desc] NVARCHAR(50))
INSERT INTO #table_a (id, [desc])
VALUES
(221, 'aaa'),(222, 'sss'),
(223, 'ddd'),(225, 'fff')
DECLARE #table_b TABLE (idcon INT, iddesc NVARCHAR(50))
INSERT INTO #table_b (idcon, iddesc)
VALUES
(221, 'zxc'),(221, 'sad'),
(221, 'fdfg'),
(222, 'asd'),(222, 'vcx'),
(223, 'zxc'),(223, 'asd'),
(224, 'cxv'),(224, 'asd'),
(225, 'zcx'),(225, 'asd'),
(225, 'qwe'),(225, 'wer')
SELECT
idcon
, [desc] = iddesc
, count1
, count2 = ROW_NUMBER() OVER (PARTITION BY id ORDER BY [desc]) - 1
FROM (
SELECT *, count1 = ROW_NUMBER() OVER (ORDER BY id)
FROM #table_a
) a
JOIN #table_b ON id = idcon
Results:
idcon desc count1 count2
------- ------ ------- -------
221 zxc 1 0
221 sad 1 1
221 fdfg 1 2
222 asd 2 0
222 vcx 2 1
223 zxc 3 0
223 asd 3 1
225 zcx 4 0
225 asd 4 1
225 qwe 4 2
225 wer 4 3
Try this
SELECT
DENSE_RANK() OVER (ORDER BY idcon) AS Count1
, (ROW_NUMBER() OVER (PARTITION BY idcon ORDER BY idcon)) - 1 AS Count2
, idcon
, iddesc
FROM Table_b b
INNER JOIN Table_a a ON a.ID = b.idcon
Here is SQLFiddle demo