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
Related
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).
The new_commsstream column below calculates if the previous row's date, partitioned by persondid and ordered by a few other columns including the date in a subquery, is greater than 90 days and returns a 1 if it is and a 0 otherwise:
create view Motability_Dataset_Staging_cmp as
select
mdsc.PersonID,
mdsc.AddressID,
mdsc.Email,
mdsc.Reportdate_month,
mdsc.Channel,
mdsc.CommsMedium,
mdsc.Campaign_Name,
mdsc.Category,
mdsc.MRM_Campaign_code,
mdsc.Action_id,
mdsc.NumSents,
mdsc.ReportDate,
isnull(cmp.ppersonid,mdsc.PersonID) as Prev_PersonID,
isnull(cmp.paddressid,mdsc.AddressID) as Prev_AddressID,
isnull(cmp.pmrmcampaigncode,mdsc.MRM_Campaign_code) as Prev_MRMCampaignCode,
isnull(cmp.pactionid,mdsc.Action_id) as Prev_ActionID,
isnull(cmp.preportdate,mdsc.ReportDate) as Prev_ReportDate,
isnull(cmp.commsdaysinterval,0) as Prev_CommsDays,
isnull(cmp.newcommsstream,0) as New_CommsStream
from Motability_Dataset_Staging as mdsc
left join
(select
cmp.row +1 as row,pcmp.row as prow,
cmp.personid as personid,pcmp.personid as ppersonid,
cmp.addressid as addressid,pcmp.addressid as paddressid,
cmp.MRM_Campaign_code as mrmcampaigncode,pcmp.MRM_Campaign_code as pmrmcampaigncode,
cmp.Action_id as actionid,pcmp.Action_id as pactionid,
cmp.reportdate as reportdate,pcmp.reportdate as preportdate,
datediff(day,cmp.ReportDate,pcmp.ReportDate) as commsdaysinterval,
case when datediff(day,cmp.ReportDate,pcmp.ReportDate) <-90 then 1 else 0 end as newcommsstream
from
(select row_number() over(partition by personid order by personid,addressid,reportdate,mrm_campaign_code,action_id)-1 as row,personid,addressid,MRM_Campaign_code,action_id,reportdate from Motability_Dataset_Staging) cmp
inner join (select row_number() over(partition by personid order by personid,addressid,reportdate,mrm_campaign_code,action_id) as row,personid,addressid,MRM_Campaign_code,action_id,reportdate from Motability_Dataset_Staging) pcmp on cmp.row = pcmp.row and cmp.personid=pcmp.personid
) cmp
on mdsc.PersonID = cmp.personid and mdsc.AddressID = cmp.addressid and mdsc.MRM_Campaign_code=cmp.mrmcampaigncode
I'm struggling to then partition by person id and new_commsstream so every time there's a 1 within the same personid it adds a new row number otherwise returns a 1:
personid new_commsstream row
1 0 1
1 0 1
1 0 1
1 1 2
1 0 2
2 0 1
3 0 1
4 0 1
5 0 1
5 1 2
5 1 3
Any ideas how to achieve this?
Thanks.
I'm not sure if it helps but you do not need to SELECT data for ROW_NUMBER() twice.
You can just place it into a SQL Server CTE exression as follows
Then you can refer to it twice
;with cmp as (
select
row_number() over(partition by personid order by addressid,reportdate,mrm_campaign_code,action_id) as row,
personid,
addressid,
MRM_Campaign_code,
action_id,
reportdate
from Motability_Dataset_Staging
), cmp2 as (
select
cmp2.*, -- previous values
cmp.* --
from cmp
left join cmp as cmp2 -- previous
cmp.row = cmp2.row + 1
)
select
mdsc.PersonID,
mdsc.AddressID,
mdsc.Email,
mdsc.Reportdate_month,
mdsc.Channel,
mdsc.CommsMedium,
mdsc.Campaign_Name,
mdsc.Category,
mdsc.MRM_Campaign_code,
mdsc.Action_id,
mdsc.NumSents,
mdsc.ReportDate,
isnull(cmp.ppersonid,mdsc.PersonID) as Prev_PersonID,
isnull(cmp.paddressid,mdsc.AddressID) as Prev_AddressID,
isnull(cmp.pmrmcampaigncode,mdsc.MRM_Campaign_code) as Prev_MRMCampaignCode,
isnull(cmp.pactionid,mdsc.Action_id) as Prev_ActionID,
isnull(cmp.preportdate,mdsc.ReportDate) as Prev_ReportDate,
isnull(cmp.commsdaysinterval,0) as Prev_CommsDays,
isnull(cmp.newcommsstream,0) as New_CommsStream
from Motability_Dataset_Staging as mdsc
inner join cmp on ......
Please see fiddle: http://sqlfiddle.com/#!6/e6768/2
I have data, like below:
DRIVER DROP
1 1
1 2
1 ReturnToBase
1 4
1 5
1 ReturnToBase
1 6
1 7
2 1
2 2
2 ReturnToBase
2 4
I am trying to group my data, so for each driver, each group of return to bases have a grouping number.
My output should look like this:
DRIVER DROP GROUP
1 1 1
1 2 1
1 ReturnToBase 1
1 4 2
1 5 2
1 ReturnToBase 2
1 6 3
1 7 3
1 ReturnToBase 3
2 1 1
2 2 1
2 ReturnToBase 1
2 4 2
I've tried getting this result with a combination of windowed functions but I've been miles off so far
Below is what I had so far, it isn't supposed to be functional I was trying to figure out how it could be done, if it's even possible.
SELECT
ROW_NUMBER() OVER (Partition BY Driver order by Driver Desc) rownum,
Count(1) OVER (Partition By Driver Order By Driver Desc) counter,
Count
DropNo,
Driver,
CASE DropNo
WHEN 'ReturnToBase' THEN 1 ELSE 0 END AS EnumerateRound
FROM
Rounds
You can use the following query:
SELECT id, DRIVER, DROPno,
1 + SUM(flag) OVER (PARTITION BY DRIVER ORDER BY id) -
CASE
WHEN DROPno = 'ReturnToBase' THEN 1
ELSE 0
END AS grp
FROM (
SELECT id, DRIVER, DROPno,
CASE
WHEN DROPno = 'ReturnToBase' THEN 1
ELSE 0
END AS flag
FROM rounds ) AS t
Demo here
This query uses windowed version of SUM with ORDER BY in the OVER clause to calculate a running total. This version of SUM is available from SQL Server 2012 onwards AFAIK.
Fiddling a bit with this running total value is all we need in order to get the correct GROUP value.
EDIT: (credit goes to #Conrad Frix)
Using CROSS APPLY instead of an in-line view can considerably simplify things:
SELECT id, DRIVER, DROPno,
1 + SUM(x.flag) OVER (PARTITION BY DRIVER ORDER BY id) - x.flag
FROM rounds
CROSS APPLY (SELECT CASE WHEN DROPno = 'ReturnToBase' THEN 1 ELSE 0 END) AS x(flag)
Demo here
Added a sequential ID column to your example for use in a recursive CTE:
with cte as (
select ID,DRIVER,DROPno,1 as GRP
FROM rounds
where ID = 1
union all
select a.ID
,a.DRIVER
,a.DROPno
,case when b.DROPno = 'ReturnToBase'
or b.DRIVER <> a.DRIVER then b.GRP + 1
else b.GRP end
from rounds a
inner join cte b
on a.ID = b.ID + 1
)
select * from cte
SQL Fiddle
There is a table with below structure:
ID XID RChange
1 1 1
2 2 1
3 3 1
4 1 0
5 2 0
6 3 1
ID column is an identity column
XID column will have some values repeating
RChange will have either 1 or 0
I need those rows from the table with RChange column value changing from 1 to 0 with same XID
i.e. in the above table, for XID 1 and 2 RChange value has changed from 1 to 0 but for XID 3 it has changed from 1 to 1.
So, I need to write a query which will retrieve
ID XID RChange
4 1 0
5 2 0
So, please help me with your ideas.
You have not included a timestamp so I am assuming the ID column will determine the order.
;WITH byXID AS
(
SELECT ID, XID, RChange, ROW_NUMBER() OVER(PARTITION BY XID ORDER BY ID) rn
FROM Table1
)
SELECT t1.ID, t1.XID, t1.RChange
FROM byXID t1
INNER JOIN byXID t0 ON t1.XID = t0.XID AND t0.rn = t1.rn - 1
WHERE t1.RChange = 0 AND t0.RChange = 1
SQL Fiddle demo
This is another approach:
SELECT t2.ID, t2.XID, t2.RChange
FROM Table1 t1 JOIN Table1 t2
ON t1.XID = t2.XID
WHERE t1.RChange = 1 AND t2.RChange = 0
Sql fiddle demo (Thanks #Ic. for the fiddle)
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