I need to execute a UDF within a query statement and its parameter depends on the current row in the larger query. I need to get a scalar from another table and pass that to the UDF however I get syntax errors if I try to use a query within the parameters of a UDF.
Example:
SELECT M.Col1
FROM MyTable M
WHERE M.RemoteID = UDFLookupRemoteID(SELECT W.Name
FROM WidgetNames W
WHERE W.Col2 = M.RemoteID)
The select within the UDF cannot be done elsewhere since it depends on the outer query.
What's the correct syntax for this?
I think this will give you what you need.
SELECT m.col1
FROM mytable m
INNER JOIN widgetnames w
ON w.col2 = m.remoteid
WHERE m.remoteid = Udflookupremoteid(w.name)
Here's an example I tested with the AdventureWorks database
SELECT pr.*
FROM production.productreview pr
INNER JOIN production.product p
ON p.productid = pr.productid
WHERE pr.rating < dbo.Ufngetstock(p.productid)
Related
I need help in optimizing this SQL query.
In the main SELECT statement there are three columns which is dependent on the outer query result. This is why my query is taking a long time to return data. I have tried making left joins but this is not working properly.
Can anyone help me to resolve this issue?
SELECT
DISTINCT ou.OrganizationUserID AS StudentID,
ou.FirstName,
ou.LastName,
(
SELECT
STRING_AGG(
(ug.UG_Name),
','
)
FROM
Groups ug
INNER JOIN ApplicantUserGroup augm ON augm.AUGM_UserGroupID = ug.UG_ID
WHERE
augm.AUGM_OrganizationUserID = ou.OrganizationUserID
AND ug.UG_IsDeleted = 0
AND augm.AUGM_IsDeleted = 0
) AS UserGroups,
order1.OrderNumber AS OrderId -- UAT-2455
,
(
SELECT
STRING_AGG(
(CActe.CustomAttribute),
','
)
FROM
CustomAttributeCte CActe
WHERE
CActe.HierarchyNodeID = dpm.DPM_ID
AND CActe.OrganizationUserID = ps.OrganizationUserID
) AS CustomAttributes -- UAT-2455
,
(
SELECT
STRING_AGG(
(CActe.CustomAttributeID),
','
)
FROM
CustomAttributeCte CActe
WHERE
CActe.HierarchyNodeID = dpm.DPM_ID
AND CActe.OrganizationUserID = ps.OrganizationUserID
) AS CustomAttributeID
FROM
ApplicantData acd WITH (NOLOCK)
INNER JOIN ClientPackage ps WITH (NOLOCK) ON acd.ClientSubscriptionID = ps.ClientSubscriptionID
INNER JOIN [ClientOrder] order1 WITH (NOLOCK) ON order1.OrderID = ps.OrderID
AND order1.IsDeleted = 0
INNER JOIN OUser ou WITH (NOLOCK) ON ou.OrganizationUserID = ps.OrganizationUserID
It looks like this query can be simplified, and the dependent subqueries in your SELECT clause removed, Consider your second and third dependent subqueries. You can refactor them into one nondependent subquery with a LEFT JOIN. Using nondependent subqueries is more efficient because the query planner can run them just once, rather than once for each row.
You want two STRING_AGG() results from the same table. This subquery gives those two outputs for every possible combination of HierarchyNodeID and OrganizationUserID values. STRING_AGG() is an aggregate function like SUM() and so works nicely with GROUP BY.
SELECT HierarchyNodeID, OrganizationUserID,
STRING_AGG((CActe.CustomAttribute), ',') CustomAttributes -- UAT-2455,
STRING_AGG((CActe.CustomAttributeID), ',') CustomAttributeIDs -- UAT-2455
FROM CustomAttributeCte CActe
GROUP BY HierarchyNodeID, OrganizationUserID
You can run this subquery itself to convince yourself it works.
Now, we can LEFT JOIN that into your query. Like this. (For readability I took out the NOLOCKs and used JOIN: it means the same thing as INNER JOIN.)
SELECT DISTINCT
ou.OrganizationUserID AS StudentID,
ou.FirstName,
ou.LastName,
'tempvalue' AS UserGroups, -- shortened for testing
order1.OrderNumber AS OrderId, -- UAT-2455
uat2455.CustomAttributes, -- UAT-2455
uat2455.CustomAttributeIDs -- UAT-2455
FROM ApplicantData acd
JOIN ClientPackage ps
ON acd.ClientSubscriptionID = ps.ClientSubscriptionID
JOIN ClientOrder order1
ON order1.OrderID = ps.OrderID
AND order1.IsDeleted = 0
JOIN OUser ou
ON ou.OrganizationUserID = ps.OrganizationUserID
LEFT JOIN (
SELECT HierarchyNodeID, OrganizationUserID,
STRING_AGG((CActe.CustomAttribute), ',') CustomAttributes -- UAT-2455,
STRING_AGG((CActe.CustomAttributeID), ',') CustomAttributeIDs -- UAT-2455
FROM CustomAttributeCte CActe
GROUP BY HierarchyNodeID, OrganizationUserID
) uat2455
ON uat2455.HierarchyNodeID = dpm.DPM_ID
AND uat2455.OrganizationUserId = ps.OrganizationUserID
See how we collapsed your second and third dependent subqueries to just one, then used it as a virtual table with LEFT JOIN? We transformed the WHERE clauses from the dependent subqueries into an ON clause.
You can test this: run it with TOP(50) and eyeball the results.
When you're happy, the next step is to transform your first dependent subquery the same way.
Pro tip Don't use WITH (NOLOCK), ever, unless a database administration expert tells you to after looking at your specific query. If your query's purpose is a historical report and you don't care whether the most recent transactions in your database are represented exactly right, you can precede your query with this statement. It also allows the query to run while avoiding locks.
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
Pro tip Be obsessive about formatting your queries for readability. You, your colleagues, and yourself a year from now must be able to read and reason about queries like this.
So I want to make the product between the sum of the number of days that a prisoner has worked and the multiplication coefficient for the specific task.
I tried this code:
UPDATE prisoners
SET nr_days_equaled = (SELECT COALESCE (multiplication_coefficient*SUM(nr_days_worked),0)
FROM prisoners pr
INNER JOIN timesheets_prisoners tp ON pr.idprisoner= tp.idprisoner
INNER JOIN nomenclature_activities_prisoners nap ON pp.idactivity=nap.idactivity)
But I get the following error:
column "nap.multiplication_coefficient" must appear in the GROUP BY clause or be used in an aggregate function
What can I do? Any ideas?
Welcome to StackOverflow.
When using any aggregate function (SUM, COUNT, MIN MAX etc.) together with any other field in your select statement, you must GROUP By the other fields selected. So in your case the compiler wants:
UPDATE prisoners
SET nr_days_equaled =
(SELECT COALESCE (multiplication_coefficient*SUM(nr_days_worked),0)
FROM prisoners pr INNER JOIN timesheets_prisoners tp
ON pr.idprisoner= tp.idprisoner
INNER JOIN nomenclature_activities_prisoners nap
ON pp.idactivity=nap.idactivity GROUP BY multiplication_coefficient)
However, without seeing the inner structure of your tables, I suspect that this is not really what you want. My suspicion is that you really need
SET nr_days_equaled =
(SELECT COALESCE (SUM(multiplication_coefficient*nr_days_worked),0)
FROM prisoners pr INNER JOIN timesheets_prisoners tp
ON pr.idprisoner= tp.idprisoner
INNER JOIN nomenclature_activities_prisoners nap
ON pp.idactivity=nap.idactivity)
The difference is that this version allows for different multiplication_coefficients for different work, but still sums the total. I stress that I am not sure. Please test by converting this to a SELECT statement before issuing the UPDATE.
EDIT
Having seen the structure, what you need is:
UPDATE prisoners
SET nr_days_equaled = SubQ.sumdaysmult
FROM
(SELECT pr.idprisoner, COALESCE (ppnap.sumdaysmult, 0) AS sumdaysmult FROM
FROM prisoners pr LEFT JOIN (SELECT tp.idprisoner, SUM(tp.nr_days_worked
* nap.multiplication_coefficient) as sumdaysmult
FROM timesheets_prisoners tp
INNER JOIN nomenclature_activities_prisoners nap
ON tp.idactivity=nap.idactivity GROUP BY tp.idprisoner) tpnap
ON tpnap.idprisoner = pr.idprisoner) AS SubQ
WHERE SubQ.idprisoner = prisoners.idprisoner
You should use group by using nap.multiplication_coefficient
------ SOLVED --------
Instead of trying to perform the subtraction within the scope of the CTE, I just had to place it into the sub query which was using this particular CTE, in the main select list.
The Problem was, `InnerOQLI.FreePlaceCount is not being recognized, since it hasn't been defined within the scope of the CTE and is only being used in the Exists statement.
------ PROBLEM ----------
This is the first time I've used CTE's, I've joined multiple CTE's together so that I can retrieve an overall total in a single column.
I need to perform a subtraction within one of the CTE's
I first wrote it like this
MyCount2
AS
(
SELECT DISTINCT
O.ID AS OrderID,
(
(
(SELECT SUM(InnerOC.[Count])
FROM Order InnerO
INNER JOIN SubOrder InnerSO ON InnerO.ID = InnerSO.OrderID
INNER JOIN OrderComponent InnerOC ON SO.ID = OC.SubOrderID
WHERE OC.OrderComponentTypeID IN (1,2,4,5)
AND EXISTS (SELECT * FROM OrderQuoteLineItem InnerOQLI
WHERE InnerOQLI.OrderQuoteLineItemTypeID = 9 AND Order.ID = InnerO.ID)
AND Inner0.ID = ).ID)
)
- --< Minus Here
OQLI.FreePlaceCount
) AS [SHPCommExpression2]
FROM Order O
INNER JOIN SubOrder SO ON O.ID = SO.OrderID
INNER JOIN OrderComponent OC ON SO.ID = OC.SubOrderID
INNER JOIN OrderQuoteLineItem OQLI ON SO.ID = 0QLI.SubOrderID
),
Without going into to much detail, this brings back incorrect data because of repeated rows in the main query. (I believe it cos of the same joins within the main query)
So I then wrote this
MyCount2
AS
(SELECT InnerO.ID AS OrderID
SUM(InnerOC.[Count]
- InnerOQLI.FreePlaceCount) --- Tried to place subtraction here ----
AS [SHPCommExpression12])
FROM Order InnerO
INNER JOIN SubOrder InnerSO ON InnerO.ID = InnerSO.OrderID
INNER JOIN OrderComponent InnerOC ON SO.ID = OC.SubOrderID
WHERE OC.OrderComponentTypeID IN (1,2,4,5)
AND EXISTS (SELECT * FROM OrderQuoteLineItem InnerOQLI
WHERE InnerOQLI.OrderQuoteLineItemTypeID = 9 AND Order.ID = InnerO.ID)
GROUP BY InnerO.ID)
),
You can see where I've attempted to perform the subtraction, but It doesn't recognize InnerOQLI, where I've tried to add it to perform the subtraction. I can't work out how to correct this, I realize that it cant fully recognize the InnerOQLI since it's in the Exists statement, Is there away around this? If anyone could help I'd appreciate it
Thanks
Instead of trying to perform the subtraction within the scope of the CTE, I just had to place it into the sub query which was using this particular CTE, in the main select list.
The Problem was, `InnerOQLI.FreePlaceCount is not being recognized, since it hasn't been defined within the scope of the CTE and is only being used in the Exists statement.
I have the query below working, the thing is I need to only list each unique "VolumeSerialNumber0" once. There's no shortage of questions and approaches to this problem on SO but they suggest using subqueries and group by clause, but when I try to do that I get an error "columnname is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
I feel like it has to be close I'm just not getting the magical syntax perfectly correct.
SELECT
dbo.v_R_System.Netbios_Name0,
dbo.v_GS_LOGICAL_DISK.TimeStamp,
dbo.v_GS_LOGICAL_DISK.Description0,
dbo.v_GS_LOGICAL_DISK.DeviceID0,
dbo.v_GS_LOGICAL_DISK.DriveType0,
dbo.v_GS_LOGICAL_DISK.Name0,
dbo.v_GS_LOGICAL_DISK.SystemName0,
dbo.v_GS_LOGICAL_DISK.VolumeName0,
dbo.v_GS_LOGICAL_DISK.VolumeSerialNumber0,
dbo.v_GS_PARTITION.Size0,
dbo.v_GS_LOGICAL_DISK.FileSystem0
FROM
dbo.v_R_System
INNER JOIN dbo.v_GS_LOGICAL_DISK
ON dbo.v_R_System.ResourceID = dbo.v_GS_LOGICAL_DISK.ResourceID
INNER JOIN dbo.v_GS_PARTITION
ON dbo.v_GS_LOGICAL_DISK.ResourceID = dbo.v_GS_PARTITION.ResourceID
SELECT
MAX(S.Netbios_Name0),
MAX(L.TimeStamp),
MAX(L.Description0),
MAX(L.DeviceID0),
MAX(L.DriveType0),
MAX(L.Name0),
MAX(L.SystemName0),
MAX(L.VolumeName0),
L.VolumeSerialNumber0,
MAX(P.Size0),
MAX(L.FileSystem0)
FROM
dbo.v_R_System S
INNER JOIN dbo.v_GS_LOGICAL_DISK L
ON S.ResourceID = L.ResourceID
INNER JOIN dbo.v_GS_PARTITION P
ON L.ResourceID = P.ResourceID
GROUP BY
L.VolumeSerialNumber0
I am trying to sum the total price from invoices (named Total_TTC in table FACT) depending on the code of the taker ( named N_PRENEUR in the two concerned tables) and store the result in the DEBIT_P column of the table table_preneur.
Doing so i get a syntax error (missing operator) In access and can't seem to understand why. I tried other posts and the usggestions returned me the same error.
UPDATE P
SET DEBIT_P = t.somePrice
FROM table_preneur AS P INNER JOIN
(
SELECT
N_PRENEUR,
SUM(Total_TTC) somePrice
FROM
FACT
GROUP BY N_PRENEUR
) t
ON t.N_PRENEUR = p.N_PRENEUR
thx in advance
with cte as
(select t.somePrice
from table_preneur as P
inner join (select SUM(Total_TTC) as somePrice
from FACT
group by N_PRENEUR) t
on t.N_PRENEUR = p.N_PRENEUR)
update P
set DEBIT_P = cte.somePrice
-- DO YOU NEED A WHERE CLAUSE?
--or maybe
update table_preneur
set DEBIT_P = (select t.somePrice
from table_preneur as P
inner join (select SUM(Total_TTC) as somePrice
from FACT
group by N_PRENEUR) t
on t.N_PRENEUR = p.N_PRENEUR)
You're missing the as keyword before your column alias somePrice:
UPDATE P
SET DEBIT_P = t.somePrice
FROM table_preneur AS P INNER JOIN
(
SELECT
N_PRENEUR,
SUM(Total_TTC) as somePrice
FROM
FACT
GROUP BY N_PRENEUR
) t
ON t.N_PRENEUR = p.N_PRENEUR
Just to clarify the above, in MS Access SQL, you need to use AS when declaring a table alias - this is missing from your SQL (SUM(Total_TTC) AS somePrice)