A group by challenge - sql-server

Let's say I have this table MyTbl
Record Id_try Id Type IsOk DateOk
1 1 MYDB00125 A 0 NULL
2 1 MYDB00125 B 1 2012-07-19 20:10:05.000
3 1 MYDB00125 A 0 2012-07-25 14:10:05.000
4 2 MYDB00125 A 0 2012-07-19 22:10:05.000
5 1 MYDB00254 B 0 2012-07-19 22:10:05.000
6 1 MYDB00254 A 0 NULL
7 3 MYDB00125 A 1 2012-07-19 22:15:05.000
8 3 MYDB00125 B 1 2012-07-19 22:42:53.000
9 1 MYDB00323 A 1 2012-07-22 00:15:05.00 0
10 1 MYDB00323 C 0 NULL
And I want a group by that brings me for each Id and Type my last "Id_Try Record".
SELECT Id, MAX(Id_Try), MyTbl.Type, IsOK, MAX(DateOk) from MyTbl
GROUP BY Id, MyTbl.Type, IsOK
Won't do, because It'll bring me the last Id_Try AND the last date (Date of record 3 in the example). And I don't care if its the last date or not, I need the date of the last Id_Try.
Is this only solved by a subselect? or a having clause could do?
This is the result expected:
Record Id_try Id Type IsOk DateOk
5 1 MYDB00254 B 0 2012-07-19 22:10:05.000
6 1 MYDB00254 A 0 NULL
7 3 MYDB00125 A 1 2012-07-19 22:15:05.000
8 3 MYDB00125 B 1 2012-07-19 22:42:53.000
9 1 MYDB00323 A 1 2012-07-22 00:15:05.00 0
10 1 MYDB00323 B 0 NULL

I think you will need to break this into two pieces:
with maxIDTry as
(
SELECT MAX(Id_try) as maxId, ID
FROM MyTable
GROUP BY ID
)
SELECT * FROM MyTable as mt
INNER JOIN maxIDTry as max
ON mt.id_try = max.maxId AND mt.id = max.id

I think you want this:
select * FROM
(
select *, row_number() over (partition by id,type order by Id_try desc) as position from mytbl
) foo
where position = 1
order by record
http://www.sqlfiddle.com/#!3/95742/5
Your sample result set lists
9 1 MYDB00323 A 1 2012-07-22 00:15:05.00 0
10 1 MYDB00323 A 0 NULL
But that doesn't make sense since you're saying the ID and the Id_try have the same value. I assume you meant for Id_try to be 2 maybe? Otherwise I think my results match up.

Hope this helps.
SELECT A.Record, A.Id_try, A.Id, A.Type, A.IsOk, A.DateOk
FROM MyTbl A INNER JOIN (
SELECT MAX(Id_Try) Id_Try, Id, B1.Type
from MyTbl B1
GROUP BY Id, B1.Type) AS B
ON A.Id_Try = B.Id_Try AND A.Id = B.Id AND A.Type = B.Type
ORDER BY A.RECORD

Related

T-SQL select rows where [col] = MIN([col])

I have a data set produced from a UNION query that aggregates data from 2 sources.
I want to select that data based on whether or not data was found in only of those sources,or both.
The data relevant parts of the set looks like this, there are a number of other columns:
row
preference
group
position
1
1
111
1
2
1
111
2
3
1
111
3
4
1
135
1
5
1
135
2
6
1
135
3
7
2
111
1
8
2
135
1
The [preference] column combined with the [group] column is what I'm trying to filter on, I want to return all the rows that have the same [preference] as the MIN([preference]) for each [group]
The desired output given the data above would be rows 1 -> 6
The [preference] column indicates the original source of the data in the UNION query so a legitimate data set could look like:
row
preference
group
position
1
1
111
1
2
1
111
2
3
1
111
3
4
2
111
1
5
2
135
1
In which case the desired output would be rows 1,2,3, & 5
What I can't work out is how to do (not real code):
SELECT * WHERE [preference] = MIN([preference]) PARTITION BY [group]
One way to do this is using RANK:
SELECT row
, preference
, [group]
, position
FROM (
SELECT row
, preference
, [group]
, position
, RANK() OVER (PARTITION BY [group] ORDER BY preference) AS seq
FROM t) t2
WHERE seq = 1
Demo here
Should by doable via simple inner join:
SELECT t1.*
FROM t AS t1
INNER JOIN (SELECT [group], MIN(preference) AS preference
FROM t
GROUP BY [group]
) t2 ON t1.[group] = t2.[group]
AND t1.preference = t2.preference

Performance issue with CTE SQL Server query

We have a table with a parent child relationship, that represents a deep tree structure.
We are using a view with a CTE to query the data but the performance is poor (see code and execution plan below).
Is there any way we can improve the performance?
WITH cte (ParentJobTypeId, Id) AS
(
SELECT
Id, Id
FROM
dbo.JobTypes
UNION ALL
SELECT
e.Id, cte.Id
FROM
cte
INNER JOIN
dbo.JobTypes AS e ON e.ParentJobTypeId = cte.ParentJobTypeId
)
SELECT
ISNULL(Id, 0) AS ParentJobTypeId,
ISNULL(ParentJobTypeId, 0) AS Id
FROM
cte
A quick example of using the range keys. As I mentioned before, hierarchies were 127K points and some sections where 15 levels deep
The cte Builds, let's assume the hier results will be will be stored in a table (indexed as well)
Declare #Table table(ID int,ParentID int,[Status] varchar(50))
Insert #Table values
(1,101,'Pending'),
(2,101,'Complete'),
(3,101,'Complete'),
(4,102,'Complete'),
(101,null,null),
(102,null,null)
;With cteOH (ID,ParentID,Lvl,Seq)
as (
Select ID,ParentID,Lvl=1,cast(Format(ID,'000000') + '/' as varchar(500)) from #Table where ParentID is null
Union All
Select h.ID,h.ParentID,cteOH.Lvl+1,Seq=cast(cteOH.Seq + Format(h.ID,'000000') + '/' as varchar(500)) From #Table h INNER JOIN cteOH ON h.ParentID = cteOH.ID
),
cteR1 as (Select ID,Seq,R1=Row_Number() over (Order by Seq) From cteOH),
cteR2 as (Select A.ID,R2 = max(B.R1) From cteOH A Join cteR1 B on (B.Seq Like A.Seq+'%') Group By A.ID)
Select B.R1
,C.R2
,A.Lvl
,A.ID
,A.ParentID
Into #TempHier
From cteOH A
Join cteR1 B on (A.ID=B.ID)
Join cteR2 C on (A.ID=C.ID)
Select * from #TempHier
Select H.R1
,H.R2
,H.Lvl
,H.ID
,H.ParentID
,Total = count(*)
,Complete = sum(case when D.Status = 'Complete' then 1 else 0 end)
,Pending = sum(case when D.Status = 'Pending' then 1 else 0 end)
,PctCmpl = format(sum(case when D.Status = 'Complete' then 1.0 else 0.0 end)/count(*),'##0.00%')
From #TempHier H
Join (Select _R1=B.R1,A.* From #Table A Join #TempHier B on A.ID=B.ID) D on D._R1 between H.R1 and H.R2
Group By H.R1
,H.R2
,H.Lvl
,H.ID
,H.ParentID
Order By 1
Returns the hier in a #Temp table for now. Notice the R1 and R2, I call these the range keys. Data (without recursion) can be selected and aggregated via these keys
R1 R2 Lvl ID ParentID
1 4 1 101 NULL
2 2 2 1 101
3 3 2 2 101
4 4 2 3 101
5 6 1 102 NULL
6 6 2 4 102
VERY SIMPLE EXAMPLE: Illustrates the rolling the data up the hier.
R1 R2 Lvl ID ParentID Total Complete Pending PctCmpl
1 4 1 101 NULL 4 2 1 50.00%
2 2 2 1 101 1 0 1 0.00%
3 3 2 2 101 1 1 0 100.00%
4 4 2 3 101 1 1 0 100.00%
5 6 1 102 NULL 2 1 0 50.00%
6 6 2 4 102 1 1 0 100.00%
The real beauty of the the range keys, is if you know an ID, you know where it exists (all descendants and ancestors).

Merge two tables based on Join - SQL Server 2012

My 1st table
select *
from dbo.tblusertasks
id pagename search _update _delete _insert
1 CustomerMaster 0 0 0 0
2 OrganizationMaseter 0 0 0 0
3 Vendor/SupplierMaster 0 0 0 0
My 2nd Table
select *
from dbo.tblpages
id pagenameid userid createdby search _update _delete _insert
1 1 1 1 1 1 1 1
2 2 1 1 1 1 1 1
I want to merge these two and need the result as
id pagename search _update _delete _insert
1 CustomerMaster 1 1 1 1
2 OrganizationMaseter 1 1 1 1
3 Vendor/SupplierMaster 0 0 0 0
I have tried this query but its not working
SELECT
pg.id, pg.[pagename], tblp.[search],tblp.[_update] ,
tblp.[_delete], tblp.[_insert]
FROM
tblpages pg
LEFT JOIN
[tblusertasks] tblp ON tblp.pagename = pg.id
WHERE
tblp.userid = 1
It's returning (I tried both left and right join but its still returning the same):
id pagename search _update _delete _insert
1 CustomerMaster 1 1 1 1
2 OrganizationMaseter 1 1 1 1
SIcne you said you have tried both the LEFT and RIGHT JOIN and it isn't working changing the tables arounf wouldn't help. YOu will need to do this:
SELECT pg.id,
pg.[pagename],
tblp.[search],
tblp.[_update],
tblp.[_delete],
tblp.[_insert]
FROM [tblusertask] tblp
LEFT JOIN tblpages pg
ON tblp.ID = pg.pagenameid
This should work.
Hope this helps...
This gives you the flexibility to partition by PageName... count, sum etc..
SELECT pagename,
T.pagenameid,
ISNULL(T.search, 0) AS search,
ISNULL(T._update, 0) AS _update,
ISNULL(T._delete, 0) AS _delete,
ISNULL(T._insert,0) AS _insert
FROM
(
SELECT
MAX(U.ID) OVER (PARTITION BY pagename) AS pagenameid,
MAX(U.search) OVER (PARTITION BY pagename) AS search,
MAX(U._update) OVER (PARTITION BY pagename) AS _update,
MAX(U._delete) OVER (PARTITION BY pagename) AS _delete,
MAX(U._insert) OVER (PARTITION BY pagename) AS _insert
FROM
tblusertasks U
LEFT JOIN
tblpages P ON U.id=P.pagenameid
)T
INNER JOIN tblusertasks UT ON UT.id=T.pagenameid
RESULT

SQL: To obtain single record for each CourseId

I'm naive to SQL...pls help me with my below query:
I have a table named Course as shown below:
Key CourseName CourseId IsCurrentVersion
0 Course_1 A 0
1 Course_1 A 0
2 Course_1 A 1
3 Course_2 B 0
4 Course_2 B 0
5 Course_3 C 1
6 Course_4 D 0
7 Course_5 E 0
8 Course_5 E 0
9 Course_6 F 1
10 Course_6 F 1
11 Course_6 F 1
12 Course_7 G 1
13 Course_7 G 0
14 Course_7 G 0
I want the below result set:
CourseName CourseId IsCurrentVersion
Course_1 A 1
Course_2 B 0
Course_3 C 1
Course_4 D 0
Course_5 E 0
Course_6 F 1
Course_7 G 1
For records having same CourseId; IsCurrentVersion having 1 should be preferred to 0. Single records should also get displayed in output irrespective of their IsCurrentVersion values.
Database is SQL Server 2008.
Try this:
SELECT CourseName, CourseId, IsCurrentVersion
FROM Course AS A
WHERE IsCurrentVersion = (SELECT MAX(IsCurrentVersion)
FROM Course AS B
WHERE A.CourseId = B.CourseId)
GROUP BY CourseName, CourseID, IsCurrentVersion
This should get you what you are looking for, assuming the only values for IsCurrentVersion are 1 and 0.
SELECT CourseName, CourseId, MAX(IsCurrentVersion)
FROM Course
GROUP BY CourseName, CourseID
If the IsCurrentVersion column is a bit and not an integer, use this instead.
SELECT CourseName, CourseId, MAX(CASE WHEN IsCurrentVersion = 1 THEN 1 ELSE 0 END)
FROM Course
GROUP BY CourseName, CourseID

How to assign an alternating row number based on a table primary key?

I have a table with data named Product
ProductID ProductName
1 ABC
2 PQR
3 XYZ
4 HJK
5 LKJ
6 MNB
... ....
with many more product in it. What I want is result like this on Select query:
RowNo ProductID ProductName
1 1 ABC
1 2 PQR
2 3 XYZ
2 4 HJK
1 5 LKJ
1 6 MNB
2 7 klj
2 8 hjg
then 1,1, 2,2 1,1 for the number of records in the table. Is it possible, and if so how can I do that?
This works for your sample data which assumes ProductID is contiguous:
SELECT
CASE WHEN ProductID % 4 = 0 OR (ProductID+1) % 4 = 0 THEN 2 ELSE 1 END,
ProductID,
ProductName
FROM
Product
Now, guessing that you mean in resultset which may have gaps in ProductID
SELECT
CASE WHEN ContiguousProductID % 4 = 0 OR (ContiguousProductID+1) % 4 = 0 THEN 2 ELSE 1 END,
--ContiguousProductID,
--CASE WHEN ProductID % 4 = 0 OR (ProductID+1) % 4 = 0 THEN 2 ELSE 1 END,
ProductID,
ProductName
FROM
(
SELECT
ROW_NUMBER() OVER (ORDER BY ProductID) AS ContiguousProductID,
ProductName, ProductID
FROM
dbo.Product
) P2

Resources