Pull a separate column that matches the (min) of an aggregate function - sql

It works well so far but I am stumped from here as I am brand new to this. This query finds the closest distance match, pairing up every item in the "FAILED" folder against everything that isn't in the "FAILED" folder.
There is a column "RouteID" in the "table p" that I want to match up with the min() aggregate.
I cannot process how to make the SELECT query simply show the associated "RouteID" column from tbl p but ultimately, I want to turn this into an update query that will SET a.Route = p.Route that is associated with the min()
Any help would be appreciated.
SELECT a.name, a.Reference1,
MIN(round(ACOS(COS(RADIANS(90-a.lat))
*COS(RADIANS(90-p.latpoint))
+SIN(RADIANS(90-a.lat))
*SIN(RADIANS(90-p.latpoint))
*COS(RADIANS(a.lon-p.longpoint)))
*3958.756,2)) AS 'DISTANCE'
FROM tblOrder AS a WITH (NOLOCK)
LEFT JOIN
(
SELECT b.lat AS latpoint, b.lon AS longpoint,
b.Sequence, b.routeid
from tblOrder b WITH (NOLOCK)
WHERE b.CUSTID = 180016
AND b.routeID <> 'FAILED'
AND b.StopType = 1
) AS p ON 1=1
WHERE a.CustID = 180016
AND a.RouteID = 'FAILED'
AND a.StopType = 1
AND P.RouteID <> 'FAILED'
GROUP BY
a.name, a.Reference1

You can select them separately and then join them
SELECT c.name, c.Reference1, q.RouteID
FROM
(
SELECT a.name, a.Reference1,
MIN(round(ACOS(COS(RADIANS(90-a.lat))
*COS(RADIANS(90-p.latpoint))
+SIN(RADIANS(90-a.lat))
*SIN(RADIANS(90-p.latpoint))
*COS(RADIANS(a.lon-p.longpoint)))
*3958.756,2)) AS 'DISTANCE'
FROM tblOrder AS a WITH (NOLOCK)
LEFT JOIN
(
SELECT b.lat AS latpoint, b.lon AS longpoint,
b.Sequence, b.routeid
from tblOrder b WITH (NOLOCK)
WHERE b.CUSTID = 180016
AND b.routeID <> 'FAILED'
AND b.StopType = 1
) AS p ON 1=1
WHERE a.CustID = 180016
AND a.RouteID = 'FAILED'
AND a.StopType = 1
AND P.RouteID <> 'FAILED'
GROUP BY
a.name, a.Reference1
) c
LEFT JOIN
(
SELECT b.lat AS latpoint, b.lon AS longpoint,
b.Sequence, b.routeid
from tblOrderRouteStops b WITH (NOLOCK)
WHERE b.CUSTID = 180016
AND b.routeID <> 'FAILED'
AND b.StopType = 1
) AS q
ON q.routeID = c.DISTANCE

Related

access compare three tables

Is there a way to triple check that the data is consistent between the three tables and show if there are any discrepancies in any of the three tables?
Each table is not completely the same but they all have an EmployeeID, amount, datepaid, and CID column.
When I did with two tables I thought I had the SQL as:
SELECT tbMaster.EmployeeID, tbMaster.Amount, tbMaster.DatePaid, tbMaster.CID
FROM tbMaster LEFT JOIN tbCID ON (tbMaster.CID = tbCID.CID) AND (tbMaster.Amount = tbCID.Amount) AND (tbMaster.DatePaid = tbCID.DatePaid)
WHERE (((tbMaster.[Advance/paid])="Paid Respondent") AND ((tbCID.CID) Is Null));
It worked but if the tbCID had any discrepancies it did not catch it...
So for the three tables I thought:
SELECT tbMaster.EmployeeID, tbMaster.Amount, tbMaster.DatePaid, tbMaster.[Advance/paid], tbMaster.CID
FROM tbMaster, tbCID, table3
WHERE tbMaster.CID <> tbCID.CID
OR table3.CID <> tbMaster.CID
OR table3.CID <> tbCID.CID
OR tbMaster.Amount <> tbCID.Amount
OR table3.AMOUNT <> tbMaster.AMOUNT
OR table3.AMOUNT <> tbCID.AMOUNT
OR tbMaster.Datepaid <> tbCID.Datepaid
OR table3.DATEPAID <> tbMaster.DATEPAID
OR table3.DATEPAID <> tbCID.DATEPAID
But there is only 30 entries yet I get 5x or 6x copies and get over 30000 rows/entries in the query...
You are doing a full cross join on your three tables, so for every combination of tbMaster row, tbCID row, and table3 row where the three don't match on the three columns, a row will be returned.
If you are trying to return a tbMaster row where the CID, Amount, and DatePaid do not appear in both tbSUID and table3, you need something similar to your first query:
SELECT tbMaster.EmployeeID, tbMaster.Amount, tbMaster.DatePaid, tbMaster.CID
FROM tbMaster
LEFT JOIN tbSUID ON (tbMaster.CID = tbSUID.CID) AND (tbMaster.Amount = tbSUID.Amount) AND (tbMaster.DatePaid = tbSUID.DatePaid)
LEFT JOIN table3 ON (tbMaster.CID = table3.CID) AND (tbMaster.Amount = table3.Amount) AND (tbMaster.DatePaid = table3.DatePaid)
WHERE ((tbMaster.[Advance/paid])="Paid Respondent")
AND ((tbCID.CID) Is Null) OR (table3.CID Is Null));
If the record has to appear in just one of tbSUID and table3, replace the last "OR" with "AND".
Consider subqueries in NOT EXISTS clauses:
SELECT m.EmployeeID, m.Amount, m.DatePaid, m.[Advance/paid], m.CID
FROM tbMaster m
WHERE NOT EXISTS
(SELECT 1 FROM tbCID c
WHERE c.CID = m.CID OR c.AMOUNT = m.AMOUNT OR c.DATEPAID = m.DATEPAID)
OR NOT EXISTS
(SELECT 1 FROM table3 t
WHERE t.CID = m.CID OR t.AMOUNT = m.AMOUNT OR t.DATEPAID = m.DATEPAID)
For inverse comparisons, consider adding union queries with a source_table indicator:
SELECT m.EmployeeID, m.Amount, m.DatePaid, m.[Advance/paid], m.CID,
'tbMaster' AS [source_table]
FROM tbMaster m
WHERE NOT EXISTS
(SELECT 1 FROM tbCID c
WHERE c.CID = m.CID OR c.AMOUNT = m.AMOUNT OR c.DATEPAID = m.DATEPAID)
OR NOT EXISTS
(SELECT 1 FROM table3 t
WHERE t.CID = m.CID OR t.AMOUNT = m.AMOUNT OR t.DATEPAID = m.DATEPAID)
UNION ALL
SELECT c.EmployeeID, c.Amount, c.DatePaid, c.[Advance/paid], c.CID,
'tbCID' AS [source_table]
FROM tbCID c
WHERE NOT EXISTS
(SELECT 1 FROM tbMaster m
WHERE m.CID = c.CID OR m.AMOUNT = c.AMOUNT OR m.DATEPAID = c.DATEPAID)
OR NOT EXISTS
(SELECT 1 FROM table3 t
WHERE t.CID = c.CID OR t.AMOUNT = c.AMOUNT OR t.DATEPAID = c.DATEPAID)
UNION ALL
SELECT t.EmployeeID, t.Amount, t.DatePaid, t.[Advance/paid], t.CID,
'table3' AS [source_table]
FROM table3 t
WHERE NOT EXISTS
(SELECT 1 FROM tbMaster m
WHERE m.CID = t.CID OR m.AMOUNT = t.AMOUNT OR m.DATEPAID = t.DATEPAID)
OR NOT EXISTS
(SELECT 1 FROM tbCID c
WHERE c.CID = t.CID OR c.AMOUNT = t.AMOUNT OR c.DATEPAID = t.DATEPAID)

query won't work after pivot

I'm trying to develop a query and i got something like this
SELECT a.No,
a.Finish,
a.Shift,
a.McCode,
d.NAME,
b.ItemCode,
b.ItemName,
b.Qty,
b.LotNo,
b.Description,
CASE
WHEN b.Description LIKE '%not good%' THEN 'NG'
ELSE 'OK'
END AS OKNG,
c.ItemCode AS matcode,
c.LotNo AS matlot,
CASE
WHEN e.GroupName = 'CONTACT' THEN 'CONTACT'
ELSE 'Coil/Silver/Wire'
END AS GroupName,
( c.Qty / ( a.Qty + a.QtyNg ) ) * b.Qty AS materialused
FROM PPRDDLV a
LEFT JOIN ICMUTTRAN b
ON a.PrdNo = b.TranNo
AND a.No = b.TranId
LEFT JOIN ICMUTTRAN c
ON a.PrdNo = c.TranNo
AND a.Finish = c.DatePost
AND c.TranTypeID = 6
AND c.LotNo <> '0'
LEFT JOIN popr d
ON a.OprCode = d.Code
LEFT JOIN ICITEM e
ON c.ItemId = e.id
WHERE c.qty IS NOT NULL
AND b.ItemCode IS NOT NULL
I got around 49000 records in around 2 seconds, then I wan't to pivot a column that has 2 kind of value, so I turned it to something like this
SELECT no,
finish,
shift,
mccode,
NAME,
itemcode,
itemname,
qty,
lotno,
description,
okng,
matcode,
matlot
FROM (SELECT a.No,
a.Finish,
a.Shift,
a.McCode,
d.NAME,
b.ItemCode,
b.ItemName,
b.Qty,
b.LotNo,
b.Description,
CASE
WHEN b.Description LIKE '%not good%' THEN 'NG'
ELSE 'OK'
END AS OKNG,
c.ItemCode AS matcode,
c.LotNo AS matlot,
CASE
WHEN e.GroupName = 'CONTACT' THEN 'CONTACT'
ELSE 'Coil/Silver/Wire'
END AS GroupName,
( c.Qty / ( a.Qty + a.QtyNg ) ) * b.Qty AS materialused
FROM PPRDDLV a
LEFT JOIN ICMUTTRAN b
ON a.PrdNo = b.TranNo
AND a.No = b.TranId
LEFT JOIN ICMUTTRAN c
ON a.PrdNo = c.TranNo
AND a.Finish = c.DatePost
AND c.TranTypeID = 6
AND c.LotNo <> '0'
LEFT JOIN popr d
ON a.OprCode = d.Code
LEFT JOIN ICITEM e
ON c.ItemId = e.id
WHERE c.qty IS NOT NULL
AND b.ItemCode IS NOT NULL) AS a
PIVOT (Max(materialused)
FOR groupname IN ([CONTACT],
[Coil/Silver/Wire])) AS b
but the query won't complete even after 10 minutes, it won't even show a single records. beside that one, the first query before I used pivot, I put an order by a.no but when I executed it, the result only shows to record 105 but the query is still working and no more record was loaded.
can anyone help me find out what's going on?
thank you!
Here's the sample data collected from the inner query and the expected value after the query.
enter image description here
I realize that I selected "matcode" in the outer select while it shouldn't be there (still didn't work though, and note for the column "material used", I'll be using it later after the pivot is done)
Try using conditional aggregate instead of pivot.
SELECT no,
finish,
shift,
mccode,
NAME,
itemcode,
itemname,
qty,
lotno,
description,
okng,
matcode,
matlot,
[CONTACT] = Max(CASE WHEN GroupName = 'CONTACT' THEN materialused END),
[Coil/Silver/Wire] = Max(CASE WHEN GroupName <> 'CONTACT' THEN materialused END)
FROM (<inner query>) AS a
GROUP BY no,
finish,
shift,
mccode,
NAME,
itemcode,
itemname,
qty,
lotno,
description,
okng,
matcode,
matlot
---IF you don't have index on filter columns then try to apply for performance
SELECT a.No,
a.Finish,
a.Shift,
a.McCode,
d.NAME,
b.ItemCode,
b.ItemName,
b.Qty,
b.LotNo,
b.Description,
CASE WHEN b.Description LIKE '%not good%' THEN 'NG'
ELSE 'OK'
END AS OKNG,
c.ItemCode,
c.LotNo,
MAX(CASE WHEN e.groupname ='CONTACT' THEN ( c.Qty / ( a.Qty + a.QtyNg ) ) * b.Qty END)OVER(ORDER BY a.no) AS [CONTACT],
MAX(CASE WHEN e.groupname ='Coil/Silver/Wire' THEN ( c.Qty / ( a.Qty + a.QtyNg ) ) * b.Qty END)OVER(ORDER BY a.no) AS [Coil/Silver/Wire]
FROM PPRDDLV a WITH(NOLOCK)
LEFT JOIN ICMUTTRAN b WITH(NOLOCK)
ON a.PrdNo = b.TranNo
AND a.No = b.TranId
LEFT JOIN ICMUTTRAN c WITH(NOLOCK)
ON a.PrdNo = c.TranNo
AND a.Finish = c.DatePost
AND c.TranTypeID = 6
AND c.LotNo <> '0'
LEFT JOIN popr d WITH(NOLOCK)
ON a.OprCode = d.Code
LEFT JOIN ICITEM e
ON c.ItemId = e.id
WHERE c.qty IS NOT NULL
AND b.ItemCode IS NOT NULL

First query data is used in second query

I have a query get_product:
select A.product_id,
A.name, A.description, A.type_id,
B.series_name
product_data A
inner join
series B
on A.series_raw_id = B.series_raw_id
where A.product_id = 503061
and A.registration_type_id = 4
order by B.series_name
and second query
select B.series_name,
A.TEMPACC_STATUS
FROM
ACCESS_FACT A
inner join
**get_product** B
on A.TEMPACC_PRODUCT_ID = B.product_id
where A.TEMPACC_DATE_ID between 6717 and 6808
and A.reason_id_total = 0
group by Series_name,
STATUS
In the second query we use data from first query (get_product is the first query). How do I get that table here?
You could use the WITH clause.
For example,
WITH get_product AS
(SELECT A.product_id,
A.name,
A.description,
A.type_id,
B.series_name product_data A
INNER JOIN series B
ON A.series_raw_id = B.series_raw_id
WHERE A.product_id = 503061
AND A.registration_type_id = 4
ORDER BY B.series_name
)
SELECT B.series_name,
A.TEMPACC_STATUS
FROM ACCESS_FACT A
INNER JOIN get_product B
ON A.TEMPACC_PRODUCT_ID = B.product_id
WHERE A.TEMPACC_DATE_ID BETWEEN 6717 AND 6808
AND A.reason_id_total = 0
GROUP BY Series_name,
STATUS;
Or, you could use an INLINE VIEW
SELECT B.series_name,
A.TEMPACC_STATUS
FROM ACCESS_FACT A
INNER JOIN
(SELECT A.product_id,
A.name,
A.description,
A.type_id,
B.series_name product_data A
INNER JOIN series B
ON A.series_raw_id = B.series_raw_id
WHERE A.product_id = 503061
AND A.registration_type_id = 4
ORDER BY B.series_name
) B ON A.TEMPACC_PRODUCT_ID = B.product_id
WHERE A.TEMPACC_DATE_ID BETWEEN 6717 AND 6808
AND A.reason_id_total = 0
GROUP BY Series_name,
STATUS;

Using a group by to group a select statement

Using a group by to group a select stament
SELECT
k.Ivalue, k.JOBDESCRIPTION ,
count( k.Ivalue) as TOTAL
FROM
(SELECT
a."ID" as Ivalue, b."JOBDESCRIPTION", rq."CURRENTSTATUS"
FROM
tblG2o_Requests a
INNER JOIN
tblG2o_JOBS b ON a."JOBPOSTID" = b."ID"
INNER JOIN
(SELECT
r.REQUESTID, ir."CURRENTSTATUS"
FROM
TBLG2O_RESULTSPOOL r
INNER JOIN
tblG2o_Requests ir ON r.RequestID = ir."ID"
WHERE
r.ShortListed = '1') rq ON rq.REQUESTID = a."ID"
WHERE
"ACTIVE" = '1'
AND "DATECOMPLETED" IS NULL
ORDER BY
"REQUESTDATE" DESC) k
GROUP BY
k.JOBDESCRIPTION
What is the question? You seem to be missing the group by clause, and you do not need double quotes around field names unless you have spaces in them, and even then, if TSQL for example, you would use [] in preference.
I had to remove an ORDER BY in the subquery, that isn't allowed unless other conditions demand it (like TOP n in TSQL)
SELECT
k.Ivalue
, k.JOBDESCRIPTION
, COUNT(k.Ivalue) AS TOTAL
FROM (
SELECT
a.ID AS Ivalue
, b.JOBDESCRIPTION
, rq.CURRENTSTATUS
FROM tblG2o_Requests a
INNER JOIN tblG2o_JOBS b
ON a.JOBPOSTID = b.ID
INNER JOIN (
SELECT
r.REQUESTID
, ir.CURRENTSTATUS
FROM TBLG2O_RESULTSPOOL r
INNER JOIN tblG2o_Requests ir
ON r.RequestID = ir.ID
WHERE r.ShortListed = '1'
) rqenter
ON rq.REQUESTID = a.ID
WHERE ACTIVE = '1'
AND DATECOMPLETED IS NULL
) k
GROUP BY
k.Ivalue
, k.JOBDESCRIPTION
Finally worked
SELECT
k.Ivalue
, l.JOBDESCRIPTION
, k.TOTAL,
k.CURRENTSTATUS
FROM (
SELECT
a.ID AS Ivalue
,b.ID as JobPostID
, rq."CURRENTSTATUS"
,COUNT(a.ID) AS TOTAL
FROM tblG2o_Requests a
INNER JOIN tblG2o_JOBS b
ON a."JOBPOSTID" = b.ID
INNER JOIN (
SELECT
r."REQUESTID"
, ir."CURRENTSTATUS"
FROM TBLG2O_RESULTSPOOL r
INNER JOIN tblG2o_Requests ir
ON r."REQUESTID" = ir.ID
WHERE r."SHORTLISTED" = 1
) rq
ON rq."REQUESTID" = a.ID
WHERE ACTIVE = '1'
AND DATECOMPLETED IS NULL
GROUP BY
a.ID ,b.ID
, rq."CURRENTSTATUS" ) k
inner join tblG2o_JOBS l on k.JobPostID =l.ID
enter code here

Query for logistic regression, multiple where exists

A logistic regression is a composed of a uniquely identifying number, followed by multiple binary variables (always 1 or 0) based on whether or not a person meets certain criteria. Below I have a query that lists several of these binary conditions. With only four such criteria the query takes a little longer to run than what I would think. Is there a more efficient approach than below? Note. tblicd is a large table lookup table with text representations of 15k+ rows. The query makes no real sense, just a proof of concept. I have the proper indexes on my composite keys.
select patient.patientid
,case when exists
(
select c.patientid from tblclaims as c
inner join patient as p on p.patientid=c.patientid
and c.admissiondate = p.admissiondate
and c.dischargedate = p.dischargedate
where patient.patientid = p.patientid
group by c.patientid
having count(*) > 1000
)
then '1' else '0'
end as moreThan1000
,case when exists
(
select c.patientid from tblclaims as c
inner join patient as p on p.patientid=c.patientid
and c.admissiondate = p.admissiondate
and c.dischargedate = p.dischargedate
where patient.patientid = p.patientid
group by c.patientid
having count(*) > 1500
)
then '1' else '0'
end as moreThan1500
,case when exists
(
select distinct picd.patientid from patienticd as picd
inner join patient as p on p.patientid= picd.patientid
and picd.admissiondate = p.admissiondate
and picd.dischargedate = p.dischargedate
inner join tblicd as t on t.icd_id = picd.icd_id
where t.descrip like '%diabetes%' and patient.patientid = picd.patientid
)
then '1' else '0'
end as diabetes
,case when exists
(
select r.patientid, count(*) from patient as r
where r.patientid = patient.patientid
group by r.patientid
having count(*) >1
)
then '1' else '0'
end
from patient
order by moreThan1000 desc
I would start by using subqueries in the from clause:
select q.patientid, moreThan1000, moreThan1500,
(case when d.patientid is not null then 1 else 0 end),
(case when pc.patientid is not null then 1 else 0 end)
from patient p left outer join
(select c.patientid,
(case when count(*) > 1000 then 1 else 0 end) as moreThan1000,
(case when count(*) > 1500 then 1 else 0 end) as moreThan1500
from tblclaims as c inner join
patient as p
on p.patientid=c.patientid and
c.admissiondate = p.admissiondate and
c.dischargedate = p.dischargedate
group by c.patientid
) q
on p.patientid = q.patientid left outer join
(select distinct picd.patientid
from patienticd as picd inner join
patient as p
on p.patientid= picd.patientid and
picd.admissiondate = p.admissiondate and
picd.dischargedate = p.dischargedate inner join
tblicd as t
on t.icd_id = picd.icd_id
where t.descrip like '%diabetes%'
) d
on p.patientid = d.patientid left outer join
(select r.patientid, count(*) as cnt
from patient as r
group by r.patientid
having count(*) >1
) pc
on p.patientid = pc.patientid
order by 2 desc
You can then probably simplify these subqueries more by combining them (for instance "p" and "pc" on the outer query can be combined into one). However, without the correlated subqueries, SQL Server should find it easier to optimize the queries.
Example of left joins as requested...
SELECT
patientid,
ISNULL(CondA.ConditionA,0) as IsConditionA,
ISNULL(CondB.ConditionB,0) as IsConditionB,
....
FROM
patient
LEFT JOIN
(SELECT DISTINCT patientid, 1 as ConditionA from ... where ... ) CondA
ON patient.patientid = CondA.patientID
LEFT JOIN
(SELECT DISTINCT patientid, 1 as ConditionB from ... where ... ) CondB
ON patient.patientid = CondB.patientID
If your Condition queries only return a maximum one row, you can simplify them down to
(SELECT patientid, 1 as ConditionA from ... where ... ) CondA