Related
I have the following data to find the loop.
Table:
CREATE TABLE tblLoop
(
person1 varchar(20),
person2 varchar(20)
);
INSERT INTO tblLoop VALUES('A','B'),('A','C'),('A','D'),
('B','E'),('B','F'),
('D','G'),('D','H'),
('F','i'),
('G','J'),
('i','A'),
('J','D');
Edit: Added some more values
INSERT INTO tblLoop VALUES('X','Y'),('X','Z'),('Z','X'),('Y','W');
Records Look like:
Note: There is possibility of multiple trees like above we need to find all trees loop data.
Requirement: I need to find the persons which forms a loop. For an example in the given data we found 2 Loop's:
Loop 1: A connected with B connected with F connected with i connected with A.
Loop 2: A connected with D connected with G connected with J connected with D.
Expected result:
LoopFound
--------------------
A->B->F->i->A
A->D->G->J->D
X->Z->X
My try:
;WITH CTE_Loop AS
(
SELECT t.Person1,t.Person2,
CONVERT(VARCHAR(500), t.Person1 + '->' + t.Person2) AS [Loop],
0 AS FoundFlag
FROM tblLoop t
UNION ALL
SELECT t.Person1,t.Person2,
CONVERT(VARCHAR(500), cte.[Loop] +'->'+t.Person2) AS [Loop],
CASE WHEN CHARINDEX(t.Person2, cte.[Loop]) != 0 THEN 1 ELSE 0 END AS FoundFlag
FROM CTE_Loop cte
INNER JOIN tblLoop t ON t.Person1 = cte.Person2
WHERE cte.FoundFlag = 0 AND t.Person1 <> '-' AND t.Person2 <> '-'
)
SELECT [Loop] AS LoopFound
FROM CTE_Loop
WHERE FoundFlag = 1
GROUP BY [Loop];
SELECT
CONCAT_WS('->',t1.person1,t1.person2,t2.person2 ,t3.person2,t4.person2)
FROM tblLoop t1
left join tblLoop t2 on t1.person2 = t2.person1
left join tblLoop t3 on t2.person2 = t3.person1
left join tblLoop t4 on t3.person2 = t4.person1
where t1.person1 = 'A'AND t4.person2 IS NOT NULL
You could get the start&end of the loops assuming a hierarchy of some sort(eg. A comes before B which is before C etc) and exclude rows whose person2 does not appear as person1 (i.e the ends of the relation/chain)...
--get loops
select distinct a.person1, b.person1, b.person2 --a.person1, b.person1 :: loop range(start-end)
from tblLoop as a
join tblLoop as b on a.person1 = b.person2 and a.person1 <= b.person1 --assume a hierarchy by name (A is on a higher/or equal level than B etc)
where exists(select * from tblLoop as d where d.person1 = a.person2) --exclude dead ends (person2 which is not person1);
..and inject that into the cte. You could work out overlaps and loops without the same start&end.
(for eg. A->D->G->J->D or D->G->J->D is a loop?)
;WITH CTE_Loop AS
(
SELECT t.Person1,t.Person2,
CONVERT(VARCHAR(500), t.Person1 + '->' + t.Person2) AS [Loop],
0 AS FoundFlag
FROM tblLoop t
where t.person1 in
(
select distinct a.person1--, b.person1, b.person2 --a.person1, b.person1 :: loop range(start-end)
from tblLoop as a
join tblLoop as b on a.person1 = b.person2 and a.person1 <= b.person1 --assume a hierarchy by name (A is on a higher/or equal level than B etc)
where exists(select * from tblLoop as d where d.person1 = a.person2) --exclude dead ends (person2 which is not person1)
)
UNION ALL
SELECT t.Person1,t.Person2,
CONVERT(VARCHAR(500), cte.[Loop] +'->'+t.Person2) AS [Loop],
CASE WHEN CHARINDEX(t.Person2, cte.[Loop]) != 0 THEN 1 ELSE 0 END AS FoundFlag
FROM CTE_Loop cte
INNER JOIN tblLoop t ON t.Person1 = cte.Person2
WHERE cte.FoundFlag = 0 AND t.Person1 <> '-' AND t.Person2 <> '-'
)
SELECT [Loop] AS LoopFound
FROM CTE_Loop
WHERE FoundFlag = 1
GROUP BY [Loop];
I have this query
Update ProductionDetails P Inner join
( SELECT Distinct A.BaseCode, A.BaseScale, (A.BaseScale * B.BasePer / 100) AS BaseVal, A.TreadCode, A.TreadScale, (A.TreadScale * B.TreadPer / 100) as TreadVal, A.InterfaceCode, A.LipCode, A.LipScale,
(A.LipScale * B.HsPer / 100) as LipVal, A.CenterCode, A.CenterScale, (A.CenterScale * B.CenterPer / 100) AS CenterVal, A.StencilNo
from productionDetails A inner join
BlendMaster B on (A.InterfaceCode = b.Category AND A.BaseCode = B.Base AND A.TreadCode = B.Tread AND A.centerCode = B.center)
Where B.Status = yes
) AS ResTable on ( P.StencilNo = ResTable.StencilNo )
Set P.BaseValue = ResTable.BaseVal, P.TreadValue = ResTable.TreadVal , P.LipValue = ResTable.LipVal, P.CenterValue = ResTable.CenterVal
I need to update ProductionDetails table on BaseValue, TreadValue, CenterValue, LipValue Fields with the calculated value in (SELECT Query ... ) AS ResTable .
if i write command to select from ResTable i get value, but if i update it says error "Operation must use an updateable query". i need to run this on MS Access 2013
Here is the query for sample data
CREATE TABLE ProductionDetails(StencilNo Text, LipCode Text, LipScale Text,LipValue Number,BaseCode Text,BaseScale Number,BaseValue Number,InterfaceCode Text,CenterCode Text,CenterScale Number,CenterValue Number,TreadCode Text,TreadScale Number,TreadValue Number)
Create Table BlendMaster (Category Text, Base Text, BasePer number , HsPer number, Center text, CenterPer number, Tread text, TreadPer number)
Insert into ProductionDetails (StencilNo, LipCode , LipScale ,BaseCode ,BaseScale , InterfaceCode ,CenterCode , CenterScale , TreadCode ,TreadScale )
VALUES ('C160405234', '-', 0,'BFA10',48.44,'BF10+CEG28' , 'CEG28', 36.5, 'TRR51', 52.56)
Insert into BlendMaster (Category, Base, BasePer ,HsPer, Center , CenterPer , Tread,TreadPer )
VALUES ('BF10+CEG28', 'BFA10',25, 25, 'CEG28', 15, 'TRR51', 18)
i think update should be done like this
UPDATE p
SET P.basevalue = ResTable.baseval,
P.treadvalue = ResTable.treadval,
P.lipvalue = ResTable.lipval,
P.centervalue = ResTable.centerval
from
#productiondetails P
INNER JOIN (SELECT A.basecode,
A.basescale,
( A.basescale * B.baseper / 100 ) AS
BaseVal,
A.treadcode,
A.treadscale,
( A.treadscale * B.treadper / 100 ) AS
TreadVal,
A.interfacecode,
A.lipcode,
A.lipscale,
( A.lipscale * B.hsper / 100 ) AS
LipVal,
A.centercode,
A.centerscale,
( A.centerscale * B.centerper / 100 ) AS
CenterVal,
A.stencilno
FROM #productiondetails A
INNER JOIN #blendmaster B
ON A.interfacecode = b.category
AND A.basecode = B.base
AND A.centercode = B.center )
---WHERE B.status = 'yes' this condtiton is not present in yout 2 tables)
ResTable
ON P.stencilno = ResTable.stencilno
Here's my Count_query:
Declare #yes_count decimal;
Declare #no_count decimal;
set #yes_count=(Select count(*) from Master_Data where Received_Data='Yes');
set #no_count=(Select count(*) from Master_Data where Received_Data='No');
select #yes_count As Yes_Count,#no_count as No_Count,(#yes_count/(#yes_count+#no_count)) As Submission_Count
I am having trouble making joins on these two queries
This is the rest of the query:
Select Distinct D.Member_Id,d.Name,d.Region_Name, D.Domain,e.Goal_Abbreviation,
e.Received_Data, case when Received_Data = 'Service Not Provided' then null
when Received_Data = 'No' then null else e.Improvement end as
Percent_Improvement , case when Received_Data = 'Service Not Provided' then null
when Received_Data = 'No' then null else e.Met_40_20 end as Met_40_20
FROM (
select distinct member_Domains.*,
(case when NoData.Member_Id is null then 'Participating' else ' ' end) as Participating
from
(
select distinct members.Member_Id, members.Name, Members.Region_Name,
case when Domains.Goal_Abbreviation = 'EED Reduction' then 'EED'
When Domains.Goal_Abbreviation = 'Pressure Ulcers' then 'PRU'
when Domains.Goal_Abbreviation = 'Readmissions' then 'READ' else Domains.Goal_Abbreviation end as Domain from
(select g.* from Program_Structure as ps inner join Goal as g on ps.Goal_Id = g.Goal_Id
and ps.Parent_Goal_ID = 0) as Domains
cross join
(select distinct hc.Member_ID, hc.Name,hc.Region_Name from zsheet as z
inner join Hospital_Customers$ as hc on z.CCN = hc.Mcare_Id) as Members
) as member_Domains
left outer join Z_Values_Hospitals as NoData on member_Domains.member_ID = NoData.Member_Id
and Member_Domains.Domain = noData.ReportName) D
Left Outer JOIN
(SELECT B.Member_ID, B.Goal_Abbreviation, B.minRate, C.maxRate, B.BLine, C.Curr_Quarter, B.S_Domain,
(CASE WHEN B.Member_ID IN
(SELECT member_id
FROM Null_Report
WHERE ReportName = B.S_Domain) THEN 'Service Not Provided' WHEN Curr_Quarter = 240 THEN 'Yes' ELSE 'No' END) AS Received_Data,
ROUND((CASE WHEN minRate = 0 AND maxRate = 0 THEN 0 WHEN minRate = 0 AND maxRate > 0 THEN 1 ELSE (((maxRate - minRate) / minRate) * 100) END), .2) AS Improvement,
(CASE WHEN ((CASE WHEN minRate = 0 AND maxRate = 0 THEN 0 WHEN minRate = 0 AND maxRate > 0 THEN 1 ELSE (maxRate - minRate) / minRate END)) <= - 0.4 OR
maxRate = 0 THEN 'Yes' WHEN ((CASE WHEN minRate = 0 AND maxRate = 0 THEN 0 WHEN minRate = 0 AND maxRate > 0 THEN 1 ELSE (maxRate - minRate) / minRate END))
<= - 0.2 OR maxRate = 0 THEN 'Yes' ELSE 'No' END) AS Met_40_20
FROM (SELECT tab.Member_ID, tab.Measure_Value AS minRate, tab.Goal_Abbreviation, A.BLine, tab.S_Domain
FROM Measure_Table_Description AS tab INNER JOIN
(SELECT DISTINCT
Member_ID AS new_memid, Goal_Abbreviation AS new_measure, MIN(Reporting_Period_ID) AS BLine, MAX(Reporting_Period_ID)
AS Curr_Quarter
FROM Measure_Table_Description
WHERE (Member_ID > 1) AND (Measure_Value IS NOT NULL) AND (Measure_ID LIKE '%O%')
GROUP BY Goal_Abbreviation, Member_ID) AS A ON tab.Member_ID = A.new_memid AND tab.Reporting_Period_ID = A.BLine AND
tab.Goal_Abbreviation = A.new_measure) AS B FULL OUTER JOIN
(SELECT tab.Member_ID, tab.Measure_Value AS maxRate, tab.Goal_Abbreviation, A_1.Curr_Quarter
FROM Measure_Table_Description AS tab INNER JOIN
(SELECT DISTINCT
Member_ID AS new_memid, Goal_Abbreviation AS new_measure,
MIN(Reporting_Period_ID) AS BLine, MAX(Reporting_Period_ID)
AS Curr_Quarter
FROM Measure_Table_Description AS Measure_Table_Description_1
WHERE (Member_ID >1) AND (Measure_Value IS NOT NULL) AND (Measure_ID LIKE '%O%')
GROUP BY Goal_Abbreviation, Member_ID) AS A_1 ON tab.Member_ID = A_1.new_memid
AND tab.Reporting_Period_ID = A_1.Curr_Quarter AND
tab.Goal_Abbreviation = A_1.new_measure) AS C ON B.Member_ID = C.Member_ID
WHERE (B.Goal_Abbreviation = C.Goal_Abbreviation) ) E ON D.Member_Id = E.Member_ID AND d.Domain = E.S_Domain
ORDER BY D.Domain,D.Member_ID
How do I get a count of the 'yes'/ (count(yes)+count(no)) for each member_ID as column1 and also display the rank of each member_ID against all the member_IDs in the result as column2. I have come up with a query that generates the count for the entire table, but how do I restrict it each Member_ID.
Thanks for your help.
I haven't taken the time to digest your provided query, but if abstracted to the concept of having an aggregate over a range of data repeated on each row, you should look at using windowing functions. There are other methods, such as using a CTE to do your aggregation and then JOINing back to your detailed data. That might work better for more complex calculations, but the window functions are arguably the more elegant option.
DECLARE #MasterData AS TABLE
(
MemberID varchar(50),
MemberAnswer int
);
INSERT INTO #MasterData (MemberID, MemberAnswer) VALUES ('Jim', 1);
INSERT INTO #MasterData (MemberID, MemberAnswer) VALUES ('Jim', 0);
INSERT INTO #MasterData (MemberID, MemberAnswer) VALUES ('Jim', 1);
INSERT INTO #MasterData (MemberID, MemberAnswer) VALUES ('Jim', 1);
INSERT INTO #MasterData (MemberID, MemberAnswer) VALUES ('Jane', 1);
INSERT INTO #MasterData (MemberID, MemberAnswer) VALUES ('Jane', 0);
INSERT INTO #MasterData (MemberID, MemberAnswer) VALUES ('Jane', 1);
-- Method 1, using windowing functions (preferred for performance and syntactical compactness)
SELECT
MemberID,
MemberAnswer,
CONVERT(numeric(19,4),SUM(MemberAnswer) OVER (PARTITION BY MemberID)) / CONVERT(numeric(19,4),COUNT(MemberAnswer) OVER (PARTITION BY MemberID)) AS PercentYes
FROM #MasterData;
-- Method 2, using a CTE
WITH MemberSummary AS
(
SELECT
MemberID,
SUM(MemberAnswer) AS MemberYes,
COUNT(MemberAnswer) AS MemberTotal
FROM #MasterData
GROUP BY MemberID
)
SELECT
md.MemberID,
md.MemberAnswer,
CONVERT(numeric(19,4),MemberYes) / CONVERT(numeric(19,4),MemberTotal) AS PercentYes
FROM #MasterData md
JOIN MemberSummary ms
ON md.MemberID = ms.MemberID;
First thought is: your query is much, much too complicated. I have spent about 10 minutes now trying to make sense of it and haven't gotten anywhere, so it's obviously going to pose a long-term maintenance challenge to those within your organization going forward as well. I would really recommend you try to find some way of simplifying it.
That said, here is a simplified, general example of how to query on a calculated value and rank the results:
CREATE TABLE member (member_id INT PRIMARY KEY);
CREATE TABLE master_data (
transaction_id INT PRIMARY KEY,
member_id INT FOREIGN KEY REFERENCES member(member_id),
received_data BIT
);
-- INSERT data here
; WITH member_data_counts AS (
SELECT
m.member_id,
(SELECT COUNT(*) FROM master_data d WHERE d.member_id = m.member_id AND d.received_data = 1) num_yes,
(SELECT COUNT(*) FROM master_data d WHERE d.member_id = m.member_id AND d.received_data = 0) num_no
FROM member m
), member_data_calc AS (
SELECT
*,
CASE
WHEN (num_yes + num_no) = 0 THEN NULL -- avoid division-by-zero error
ELSE num_yes / (num_yes + num_no)
END pct_yes
FROM member_data_counts
), member_data_rank AS (
SELECT *, RANK() OVER (ORDER BY pct_yes DESC) AS RankValue
FROM member_data_calc
)
SELECT *
FROM member_data_rank
ORDER BY RankValue ASC;
Below is a complete query I have and the ultimate aim is to update the claim table. But it should be only one statement without any subquery, only joins are allowed because I am going to run this in an appliance which won't support subquery:
DECLARE #DecWdrwn as TABLE(CtryId smallint, CmId int, DecWdrwnDt int);
WITH s AS
(
SELECT
Ctryid,CmId,Dt,
ISNULL((
SELECT max(CmHistDtTmId)
FROM ClaimHistory l
WHERE St = 3
AND l.Ctryid = c.Ctryid
AND l.CmId = c.CmId)
, 0) MaxDec,
ISNULL((
SELECT max(CmHistDtTmId)
FROM ClaimHistory l
WHERE St = 7
AND l.Ctryid = c.Ctryid
AND l.CmId = c.CmId)
, 0) MaxSet
FROM
ClaimHistory c
WHERE
St =3
)
INSERT INTO #DecWdrwn
SELECT CtryId, CmId, Max(Dt) DecDt
FROM s
WHERE MaxSet > MaxDec
GROUP BY CtryId,CmId
Your response is much appreciated...
UPDATE Claims
SET CmDclnWdwnDt = (
SELECT DecWdrwnDt
FROM #DecWdrwn d
WHERE d.CmId = Claims.CmId
AND d.CtryId = Claims.CtryId
)
WHERE EXISTS (
SELECT *
FROM #DecWdrwn d
WHERE d.CmId = Claims.CmId
AND d.CtryId = Claims.CtryId
)
Please try INNER JOIN Update:
UPDATE a
SET a.CmDclnWdwnDt = b.DecWdrwnDt
FROM Claims a, #DecWdrwn b
WHERE a.CmId = b.CmId AND
a.CtryId =b.CtryId
I have this query which is pretty long, but adding a where clause to it, or joining on a string makes it take an extra 2 seconds to run. I can't figure out why.
Here's the query in full:
ALTER PROCEDURE [dbo].[RespondersByPracticeID]
#practiceID int = null,
#activeOnly bit = 1
AS
BEGIN
SET NOCOUNT ON;
select
isnull(sum(isResponder),0) as [Responders]
,isnull(count(*) - sum(isResponder),0) as [NonResponders]
,isnull((select
count(p.patientID)
from patient p
inner join practice on practice.practiceid = p.practiceid
inner join [lookup] l on p.dosing = l.lookupid and l.lookupid = 'da_ncd'
where
p.practiceID = isnull(#practiceID, p.practiceID)
and p.active = case #activeOnly when 1 then 1 else p.active end
) - (isnull(sum(isResponder),0) + isnull(count(*) - sum(isResponder),0)),0)
as [Undetermined]
from (
select
v.patientID
,firstVisit.hbLevel as startHb
,maxHbVisit.hblevel as maxHb
, case when (maxHbVisit.hblevel - firstVisit.hbLevel >= 1) then 1 else 0 end as isResponder
,count(v.patientID) as patientCount
from patient p
inner join visit v on v.patientid = v.patientid
inner join practice on practice.practiceid = p.practiceid
inner join [lookup] l on p.dosing = l.lookupid and l.lookupid = 'da_ncd'
inner join (
SELECT
p.PatientID
,v.VisitID
,v.hblevel
,v.VisitDate
FROM Patient p
INNER JOIN Visit v ON p.PatientID = v.PatientID
WHERE
v.VisitDate = (
SELECT MIN(VisitDate)
FROM Visit
WHERE PatientId = p.PatientId
)
) firstVisit on firstVisit.patientID = v.patientID
inner join (
select
p.patientID
,max(v.hbLevel) as hblevel
from Patient p
INNER JOIN Visit v ON p.PatientID = v.PatientID
group by
p.patientID
) MaxHbVisit on maxHbVisit.patientid = v.patientId
where
p.practiceID = isnull(#practiceID, p.practiceID)
and p.active = case #activeOnly when 1 then 1 else p.active end
group by
v.patientID
,firstVisit.hbLevel
,maxHbVisit.hblevel
having
datediff(
d,
dateadd(
day
,-DatePart(
dw
,min(v.visitDate)
) + 1
,min(v.visitDate)
)
, max(v.visitDate)
) >= (7 * 8) -- Eight weeks.
) responders
END
The line that slows it down is:
inner join [lookup] l on p.dosing = l.lookupid and l.lookupid = 'da_ncd'
Also, moving it to the where clause has the same effect:
where p.dosing = 'da_ncd'
Otherwise, the query runs almost instantly. >.<
Ah, sorry I figured it out. Patient.Dosing was set as allow nulls. I guess that made it a different sort of index.
For the record, even though the question is answered.
Usually things like this happen because the execution plan is changed. Compare the plans in query analyzer.
Another gotcha is data types - if p.dosing and l.lookupid differ - nvarchar vs. varchar, for example, can have a huge impact.
Try creating an index on that table, being sure to properly include that VARCHAR field in the list of fields.