SQL Update with AVG of Joined Tables - sql

I'm trying to update the supplier lead time in a table by calculating the difference between date of order and stock receipt date....
UPDATE cr_accs
SET cr_accs.leadtime = Avg(Datediff(day, purchord_hdr.orderdate,
stock_trans.transdate))
FROM stock_items
INNER JOIN stock_trans
ON stock_trans.stockcode = stock_items.stockcode
INNER JOIN purchord_hdr
ON purchord_hdr.seqno = stock_trans.ref1
WHERE cr_accs.accno = purchord_hdr.accno
AND stock_trans.location = 1
AND stock_trans.ref2 = 'RECEIPT'
AND purchord_hdr.orderdate >= Dateadd(day, Datediff(day, 0, Getdate()),-730)
AND stock_items.isactive = 'Y'
AND stock_items.bincode NOT IN ( 'OIO', 'CON' )
However I'm getting an error
An aggregate may not appear in the set list of an UPDATE statement
I've seen other solutions where you would change the query to:
UPDATE cr_accs
SET cr_accs.leadtime = h.calc_lead_time
FROM (SELECT AVG(DATEDIFF(day, purchord_hdr.orderdate, stock_trans.transdate)) AS calc_lead_time
FROM stock_items
INNER JOIN stock_trans
ON stock_trans.stockcode = stock_items.stockcode
INNER JOIN purchord_hdr
ON purchord_hdr.seqno = stock_trans.ref1
INNER JOIN cr_accs
ON cr_accs.accno = purchord_hdr.accno
WHERE cr_accs.accno = purchord_hdr.accno
AND stock_trans.location = 1
AND stock_trans.ref2 = 'RECEIPT'
AND purchord_hdr.orderdate >= Dateadd(day, Datediff(day, 0, Getdate()),-730)
AND stock_items.isactive = 'Y'
AND stock_items.bincode NOT IN ( 'OIO', 'CON' ) ) h
However this is not the solution for me as it doesn't define that the lead time is unique to each supplier...
It may be helpful to point out that each supplier is identified by cr_accs.accno
Any ideas please?

You can also do what you want using a correlated subquery, which might be what you were trying to do:
UPDATE cr_accs
SET cr_accs.leadtime =
(SELECT AVG(DATEDIFF(day, p.orderdate, st.transdate)) AS calc_lead_time
FROM stock_items si JOIN
stock_trans st
ON st.stockcode = si.stockcode JOIN
purchord_hdr p
ON p.seqno = st.ref1
WHERE cr_accs.accno = p.accno AND
st.location = 1 AND
st.ref2 = 'RECEIPT' AND
p.orderdate >= Dateadd(day, Datediff(day, 0, Getdate()), -730) AND
si.isactive = 'Y' AND
si.bincode NOT IN ( 'OIO', 'CON' )
);
I introduced table aliases so the query is easier to write and to read.
SQL Server also gives you the ability to express this using APPLY:
UPDATE a
SET a.leadtime = p.calc_lead_time
FROM cr_accs a CROSS APPLY
(SELECT AVG(DATEDIFF(day, p.orderdate, st.transdate)) AS calc_lead_time
FROM stock_items si JOIN
stock_trans st
ON st.stockcode = si.stockcode JOIN
purchord_hdr p
ON p.seqno = st.ref1
WHERE a.accno = p.accno AND
st.location = 1 AND
st.ref2 = 'RECEIPT' AND
p.orderdate >= Dateadd(day, Datediff(day, 0, Getdate()), -730) AND
si.isactive = 'Y' AND
si.bincode NOT IN ( 'OIO', 'CON' )
) p;

Try this join of the table to the query:
UPDATE c
SET c.leadtime = h.calc_lead_time
FROM cr_accs c
INNER JOIN (
SELECT purchord_hdr.accno,
AVG(DATEDIFF(day, purchord_hdr.orderdate, stock_trans.transdate)) AS calc_lead_time
FROM stock_items
INNER JOIN stock_trans ON stock_trans.stockcode = stock_items.stockcode
INNER JOIN purchord_hdr ON purchord_hdr.seqno = stock_trans.ref1
WHERE stock_trans.location = 1
AND stock_trans.ref2 = 'RECEIPT'
AND purchord_hdr.orderdate >= Dateadd(day, Datediff(day, 0, Getdate()),-730)
AND stock_items.isactive = 'Y'
AND stock_items.bincode NOT IN ('OIO', 'CON')
GROUP BY purchord_hdr.accno
) h ON h.accno = c.accno
I assume (by your code and the error message) that you are using SQL Server.

Related

How to return an extra column in a sub query that is a UNION

I want to somehow get the Promotions Id from the second select in a UNION which is a sub query that brings back one column.
Is it somehow possible to achieve this or will I have to duplicate the 2nd query somehow again?
Updated
So, basically this code will get a Promotion Price from an older Table in the same Database and then it will UNION it to a new Promotions Table and select the best or lowest price from the two, but the newer Promotion Table has a Promotion Id (P.Id) which I need to return.
Additional Unrelated Info
The DateValidFrom and DateValidTo is of type Datetime because the Promotion can have a start and end date with a specific time.
Expected Outcome
I want to return the Promotions Id which is P.Id from the Promotions Table.
ALTER FUNCTION [dbo].[GetCustomerPricingForProduct] (#StockParentId int,
#CustomerCode varchar(30),
#PricingDate date,
#ChannelID int,
#QTY int,
#CustCategoryNo int,
#PriceType int,
#CustomerDealerType int)
RETURNS table
AS
RETURN (SELECT ISNULL(F.Price, ISNULL(R.SellingPrice, 0)) AS StandardPrice,
(SELECT DiscountLines.amount
FROM Customers
INNER JOIN CustDiscounts ON Customers.pricelist = CustDiscounts.no
INNER JOIN DiscountLines ON CustDiscounts.no = DiscountLines.no
INNER JOIN FinGoodsParent FP ON FP.Id = DiscountLines.FinGoods_ID
WHERE Customer_Code = #CustomerCode
AND CONVERT(date, CustDiscounts.startdate) <= #PricingDate
AND CONVERT(date, CustDiscounts.enddate) >= #PricingDate
AND DiscountLines.TYPE = #PriceType
AND FP.Id = #StockParentId) AS PricelistPrice,
(SELECT TOP 1
Pricing
FROM (SELECT Pricing
FROM PROMGEN
INNER JOIN FinGoodsParent FP ON FP.Id = PROMGEN.FinGoods_ID
INNER JOIN PromCateg ON PROMGEN.No = PromCateg.PromGen_No
INNER JOIN PromGen_Channels ON PROMGEN.No = PromGen_Channels.PromGen_No
INNER JOIN Channels ON PromGen_Channels.Channels_Id = Channels.Id
WHERE PROMGEN.MINQUANT <= #QTY
AND #PricingDate >= CONVERT(date, PROMGEN.START_DATE)
AND #PricingDate <= CONVERT(date, PROMGEN.END_DATE)
AND Channels_Id = #ChannelID
AND PromCateg.CustCateg_No = #CustCategoryNo
AND FP.Id = #StockParentId
AND PROMGEN.TYPE = #PriceType
UNION
SELECT MIN(SP_P.PricingRuleTypeAmount) AS Pricing
FROM StockParent_Promotions SP_P
INNER JOIN Promotions P ON P.Id = SP_P.Promotions_Id
INNER JOIN Promotions_Channels PC ON PC.Promotions_Id = P.Id
INNER JOIN StockParent SP ON SP_P.StockParent_Id = SP.Id
INNER JOIN Promotions_CustCateg PCC ON PCC.Promotions_Id = P.Id
INNER JOIN CUSTCATEG CC ON CC.NO = PCC.CustCateg_No
WHERE SP_P.MinPurchaseQuantity <= #QTY
AND #PricingDate >= CONVERT(date, P.DateValidFrom)
AND #PricingDate <= CONVERT(date, P.DateValidTo)
AND Channels_Id = #ChannelID
AND PCC.CustCateg_No = #CustCategoryNo
AND SP.Id = #StockParentId
AND SP_P.PricingRuleType = #PriceType
AND ((P.IsPromotionForEndUsers = 1
AND #CustomerDealerType = 1)
OR (P.IsPromotionForDealers = 1
AND #CustomerDealerType = 0))
AND P.IsDeleted = 0) OldAndNewPromotions
WHERE Pricing IS NOT NULL
ORDER BY Pricing ASC) AS PromotionPrice
FROM StockParent
LEFT JOIN Fingoods F ON F.Id = StockParent.ID
LEFT JOIN RAWMAT R ON R.Id = StockParent.ID
WHERE StockParent.Id = #StockParentId);

Convert nested Query to Join in SQL Server

I have a query
SELECT *
FROM Stops
WHERE CustomerID IN (SELECT ID FROM Customers WHERE Active = 1)
AND DriverID IS NOT NULL
AND TripID IN (SELECT ID
FROM Trips
WHERE ManagerID IN (SELECT ID FROM Users WHERE Active = 1)
AND AssignedToID IN (SELECT ID FROM Users WHERE Active = 1)
AND Modified > DATEADD(day, -60, GETDATE()))
I tried to convert to Join but I am stuck
SELECT *
FROM Stops S
JOIN Customers C ON C.ID = S.CustomerID
JOIN Trips T ON S.TripID = T.ID
WHERE C.ACTIVE = 1
AND S.DriverID IS NOT NULL
AND T.Modified > DATEADD(day, -60, GETDATE())
Using all joins, no nested queries
SELECT * FROM Stops A
INNER JOIN Customers B ON A.CustomerID = B.ID
INNER JOIN Trips C ON A.TripID = C.ID
INNER JOIN Users D ON C.ManagerID = D.ID
INNER JOIN Users E ON C.AssignedToID = E.ID
WHERE A.DriverID IS NOT NULL AND
B.Active = 1 AND
D.Active = 1 AND
E.Active = 1 AND
C.Modified > DATEADD(day, -60, GETDATE());
If you want unique data of stops you can also add "DISTINCT" to the select.
you can try like below subquery and join
SELECT S.* FROM Stops S
JOIN Customers C ON C.ID=S.CustomerID
join (SELECT ID FROM Trips where
ManagerID IN (SELECT ID FROM Users WHERE Active = 1) AND
AssignedToID IN (SELECT ID FROM Users WHERE Active = 1) AND
Modified > DATEADD(day, -60, GETDATE())
) t on S.TripID=t.ID
I'm trying your second code on my end until I came up on the below code. You might try
SELECT *
FROM Stops S
JOIN Customers C ON C.ID = S.CustomerID AND C.ACTIVE = 1
JOIN Trips T ON S.TripID = T.ID AND T.Modified > DATEADD(day, -60, GETDATE())
LEFT JOIN Users U ON T.ManagerID = U.ID AND T.AssignedToID = U.ID
WHERE S.DriverID IS NOT NULL
What I usually do is to draw squares as tables and link them based on the requirements.
Though, still not sure if my answer would work since I have no idea with what you are trying to achieve on your code aside from using JOIN.

Count in SQL Server table

I'm using the following SQL query:
select
FilteredSystemUser.systemuserid,
FilteredPhoneCall.regardingobjectid
from
FilteredPhoneCall
Inner Join
FilteredSystemUser on FilteredSystemUser.systemuserid in (FilteredPhoneCall.createdby)
Inner Join
FilteredLead on FilteredLead.leadid = FilteredPhoneCall.regardingobjectid
where
DateDiff(d, FilteredPhoneCall.createdon, GETDATE()) = 0
and FilteredLead.statecode = 0
and FilteredLead.ownerid = FilteredSystemUser.systemuserid
and FilteredPhoneCall.statecode = '1'
and FilteredPhoneCall.regardingobjecttypecode = 4
and FilteredPhoneCall.createdby in ('c2dd1ddc-0374-e611-80dc-00155d3d1992', '53cfbe3a-a09a-e611-80df-00155dce24d0')
and get the following output
Here I have two entries in regardingid 97C29D24-BEE2-E611-80F1-00155DCE24EF,091B1CAB-C2E2-E611-80F1-00155DCE24EF against same system user.so i need to consider this as single entry and get the count other than this the both system users having another two ids.
I expect the above output
To get count of distinct values of a column reference here...
SQL: Count distinct values from one column based on multiple criteria in other columns
For your case, try this:
select
FilteredSystemUser.systemuserid,
Count(DISTINCT FilteredPhoneCall.regardingobjectid ) as NoofCall
from
FilteredPhoneCall
Inner Join
FilteredSystemUser on FilteredSystemUser.systemuserid in (FilteredPhoneCall.createdby)
Inner Join
FilteredLead on FilteredLead.leadid = FilteredPhoneCall.regardingobjectid
where
DateDiff(d, FilteredPhoneCall.createdon, GETDATE()) = 0
and FilteredLead.statecode = 0
and FilteredLead.ownerid = FilteredSystemUser.systemuserid
and FilteredPhoneCall.statecode = '1'
and FilteredPhoneCall.regardingobjecttypecode = 4
and FilteredPhoneCall.createdby in ('c2dd1ddc-0374-e611-80dc-00155d3d1992', '53cfbe3a-a09a-e611-80df-00155dce24d0')
Group by FilteredSystemUser.systemuserid
TRY THIS
;with CTE
AS (
select
FilteredSystemUser.systemuserid,
FilteredPhoneCall.regardingobjectid
from
FilteredPhoneCall
Inner Join
FilteredSystemUser on FilteredSystemUser.systemuserid in (FilteredPhoneCall.createdby)
Inner Join
FilteredLead on FilteredLead.leadid = FilteredPhoneCall.regardingobjectid
where
DateDiff(d, FilteredPhoneCall.createdon, GETDATE()) = 0
and FilteredLead.statecode = 0
and FilteredLead.ownerid = FilteredSystemUser.systemuserid
and FilteredPhoneCall.statecode = '1'
and FilteredPhoneCall.regardingobjecttypecode = 4
and FilteredPhoneCall.createdby in ('c2dd1ddc-0374-e611-80dc-00155d3d1992', '53cfbe3a-a09a-e611-80df-00155dce24d0') )
select count(CTE.systemuserid) as myCOUNT,CTE.systemuserid,CTE.regardingobjectid from CTE
group by CTE.systemuserid,CTE.regardingobjectid
You can use count() and group by to achive this.
select COUNT(DISTINCT FilteredPhoneCall.regardingobjectid ) as NoofCall
,FilteredSystemUser.systemuserid
from FilteredPhoneCall
inner Join FilteredSystemUser
on FilteredSystemUser.systemuserid in(FilteredPhoneCall.createdby)
Join FilteredLead
on FilteredLead.leadid = FilteredPhoneCall.regardingobjectid
where DateDiff(d, FilteredPhoneCall.createdon, GETDATE()) = 0
and FilteredLead.statecode = 0 and FilteredLead.ownerid = FilteredSystemUser.systemuserid
and FilteredPhoneCall.statecode = '1' and FilteredPhoneCall.regardingobjecttypecode = 4
and FilteredPhoneCall.createdby in ('c2dd1ddc-0374-e611-80dc-00155d3d1992','53cfbe3a-a09a-e611-80df-00155dce24d0')
and FilteredSystemUser.systemuserid in ('c2dd1ddc-0374-e611-80dc-00155d3d1992','53cfbe3a-a09a-e611-80df-00155dce24d0')
GROUP BY FilteredSystemUser.systemuserid

SQL Query Failed to retrieve data from database. Subquery returned more than one value

I have a problem: the query just stopped working. I have a message:
Failed to retrieve data from the database. Subquery returned more than one value.
Here is the code
SELECT DISTINCT
k.animal_i d,
a.animal_type,
a.animal_name,
a.breed_group,
k.kennel_no,
a.extra1,
(SELECT
m.memo_text
FROM
SYSADM.animal AS a
INNER JOIN
SYSADM.memo AS m ON a.animal_id = m.memo_id
WHERE
m.memo_id = k.animal_id
AND m.memo_type = 'GROOMING') AS memo,
(SELECT
tr.visit_type
FROM
SYSADM.animal AS a
INNER JOIN
SYSADM.treatment AS tr ON tr.animal_id = a.animal_id
WHERE
a.animal_id = k.animal_id
AND tr.visit_type IN ('SURGERY', 'RTO SPAYNEUTER',
'SNAPP SPAYNEUTER', 'SPAYNEUT SURG')
AND dateDiff(d, tr.treatment_date, getdate()) < 10) AS visitType,
(SELECT
tr.treatment_date
FROM
SYSADM.animal AS a
INNER JOIN
SYSADM.treatment AS tr ON tr.animal_id = a.animal_id
WHERE
a.animal_id = k.animal_id
AND tr.visit_type IN ('SURGERY', 'RTO SPAYNEUTER',
'SNAPP SPAYNEUTER', 'SPAYNEUT SURG')
AND dateDiff(d, tr.treatment_date, getdate() ) < 10) AS treatmentDate
FROM
SYSADM.kennel AS k
INNER JOIN
SYSADM.animal AS a ON k.animal_id = a.animal_id
FULL OUTER JOIN
SYSADM.memo AS m ON k.animal_id = m.memo_id
INNER JOIN
SYSADM.treatment AS tr ON tr.animal_id = a.animal_id
WHERE
k.outcome_date_null = 'Y'
AND a.extra1 IN ('BATHE', 'BATHE ASAP', 'BRUSH', 'GROOM')
AND NOT EXISTS (SELECT *
FROM SYSADM.kennel
WHERE k.outcome_type IN ('RTO', 'TRANSFER')
AND NOT k.outcome_date_null = 'Y')

SQL to grab all customers even if they don't have an order

Below is a SQL statement that grabs orders for customers. I would like to modify it, so that it will include customers that don't have an order, however I am unsure as to the best way to do this:
SELECT
CT.ACCOUNTNUM,CT.STOREGROUPID,CT.STOREID, ST.STORENAME,
CT.CITY,PT.ORIGSALESID,PT.DELIVERYDATE,PT.ITEMID,IT.BRANDID,
IT.SIZEID,IT.SPECIALTYTYPEID,SUM(PT.QTY) AS Qty,
dbo.ConvertUnitQty(PT.itemid,PT.salesunit,'DZ',PT.dataareaid,sum(pt.qty)) as ConsumeQtyDz
FROM
CUSTPACKINGSLIPTRANS PT
JOIN SALESTABLE ST ON ST.SALESID = PT.ORIGSALESID
AND ST.DATAAREAID = PT.DATAAREAID
JOIN CUSTTABLE CT ON ST.CUSTACCOUNT = CT.ACCOUNTNUM
AND ST.DATAAREAID = CT.DATAAREAID
JOIN INVENTTABLE IT ON IT.ITEMID = PT.ITEMID
AND IT.DATAAREAID = PT.DATAAREAID
WHERE
(ST.DATAAREAID = #COMPANY) AND
(PT.DELIVERYDATE BETWEEN #STARTDATE AND #ENDDATE) AND
IT.BRANDID IN (#BRANDID) AND
IT.SIZEID IN (#SIZEID) AND
IT.SPECIALTYTYPEID = (#SPECIALTYTYPE) AND
CT.ASISTOREGROUPID IN (#STOREGROUPID)
GROUP BY
CT.ACCOUNTNUM,CT.STOREGROUPID,CT.STOREID,ST.STORENAME,
CT.CITY,PT.ORIGSALESID,PT.DELIVERYDATE,PT.ITEMID,IT.BRANDID,
IT.SIZEID,IT.SPECIALTYTYPEID,PT.SALESUNIT,PT.DATAAREAID
May be like this
SELECT
CT.ACCOUNTNUM, CT.STOREGROUPID, CT.STOREID, ST.STORENAME, CT.CITY, PT.ORIGSALESID, PT.DELIVERYDATE, PT.ITEMID, IT.BRANDID, IT.SIZEID, IT.SPECIALTYTYPEID, SUM(PT.QTY) AS Qty, dbo.ConvertUnitQty(PT.itemid,PT.salesunit,'DZ',PT.dataareaid,sum(pt.qty))as ConsumeQtyDz
FROM
CUSTPACKINGSLIPTRANS PT
LEFT JOIN
SALESTABLE ST ON ST.SALESID = PT.ORIGSALESID AND ST.DATAAREAID = PT.DATAAREAID
LEFT JOIN
CUSTTABLE CT ON ST.CUSTACCOUNT = CT.ACCOUNTNUM AND ST.DATAAREAID = CT.DATAAREAID
LEFT JOIN
INVENTTABLE IT ON IT.ITEMID = PT.ITEMID AND IT.DATAAREAID = PT.DATAAREAID
WHERE
(ST.DATAAREAID = #COMPANY OR ST.DATAAREAID = IS NULL)
AND (PT.DELIVERYDATE BETWEEN #STARTDATE AND #ENDDATE)
AND (IT.BRANDID IN (#BRANDID) OR IT.BRANDID IS NULL)
AND (IT.SIZEID IN (#SIZEID) OR IT.SIZEID IS NULL)
AND (IT.SPECIALTYTYPEID = (#SPECIALTYTYPE) OR IT.SPECIALTYTYPEID IS NULL)
AND (CT.ASISTOREGROUPID IN (#STOREGROUPID) OR CT.ASISTOREGROUPID IS NULL)
GROUP BY
CT.ACCOUNTNUM, CT.STOREGROUPID, CT.STOREID, ST.STORENAME, CT.CITY, PT.ORIGSALESID, PT.DELIVERYDATE, PT.ITEMID, IT.BRANDID, IT.SIZEID, IT.SPECIALTYTYPEID, PT.SALESUNIT, PT.DATAAREAID
I'm not sure if I'm missing something, but...
SELECT * FROM [customerTable]
The minimum SQL to show every thing about every customer is:
select * from custtable;