SQL Update statement with aggregate count - sql-server

I am getting the following error
Subquery returned more than 1 value. This is not permitted when the
subquery follows =, !=, <, <= , >, >= or when the subquery is used as
an expression.
For this query:
UPDATE b
SET b.Products = (SELECT COUNT(pf.Product_Family_ID)
FROM Product_Families pf
INNER JOIN Products p ON pf.Product_Family_ID = p.Product_Family_ID
INNER JOIN Brands b2 on pf.BrandID = b2.Brand_ID
WHERE
pf.Discontinued = 0
AND pf.Live = 0
AND p.Inventory > 0
AND pf.Brand <> ''
GROUP BY
b2.Brand, b2.Brand_ID)
FROM Brands b
INNER JOIN Product_Families pf2 ON b.Brand_ID = pf2.BrandID
WHERE
b.Brand_ID = pf2.BrandID
I know I am missing just a little something. Thanks for the help.

You can't assign a non-scalar value to a scalar value. Your subquery could return a set of tuples because you are asking for a COUNT on each group. Run the subquery by itself:
(Select COUNT(pf.Product_Family_ID)
FROM Product_Families pf
INNER JOIN Products p ON pf.Product_Family_ID = p.Product_Family_ID
INNER JOIN Brands b2 on pf.BrandID = b2.Brand_ID
WHERE
pf.Discontinued = 0
AND
pf.Live = 0
AND
p.Inventory > 0
AND
pf.Brand <> ''
GROUP BY b2.Brand, b2.Brand_ID)
and you will see what it returns. You probably want a count of all the records in the subquery: take out the groupings.

As #nicomp said, Your subquery will return more than one result so just filter out the result to specific brands.
Try this:
UPDATE b
SET b.Products = Select number (SELECT COUNT(pf.Product_Family_ID) as number, b2.Brand_ID
FROM Product_Families pf
INNER JOIN Products p ON pf.Product_Family_ID = p.Product_Family_ID
INNER JOIN Brands b2 on pf.BrandID = b2.Brand_ID
WHERE
pf.Discontinued = 0
AND pf.Live = 0
AND p.Inventory > 0
AND pf.Brand <> ''
GROUP BY
b2.Brand, b2.Brand_ID)
Where Brand_ID = b.Brand_ID
FROM Brands b
INNER JOIN Product_Families pf2 ON b.Brand_ID = pf2.BrandID
WHERE
b.Brand_ID = pf2.BrandID
This is not optimized but this will fix your error.

Thank you for all the help, here is the solution that I used.
IF OBJECT_ID('tempdb..#Temp') IS NOT NULL
/*Then it exists*/
DROP TABLE #Temp
SELECT * INTO #Temp FROM (SELECT
b.Brand_ID,
b.Brand,
COUNT(pf.Product_Family_ID) PFBrandCount FROM Product_Families pf
INNER JOIN Products p ON pf.Product_Family_ID = p.Product_Family_ID
INNER JOIN Brands b on pf.BrandID = b.Brand_ID
WHERE
pf.Discontinued = 0
AND
pf.Live = 0
AND
p.Inventory > 0
AND
pf.Brand <> ''
Group BY b.Brand, b.Brand_ID) data
Update b SET Products = #Temp.PFBrandCount
FROM BRANDS b
INNER JOIN #Temp ON b.Brand_ID = #Temp.Brand_ID
DROP TABLE #Temp

Related

Join based on condition?

Is it possible to condition a join based on a condition?
For example, if #DoJoin is true then do the inner join. It would replace something like this:
declare #DoJoin bit = 1
if #DoJoin = 1
BEGIN
select T.* from T inner join L on T.col = L.col
END
ELSE
BEGIN
select T.* from T
END
If I'm understanding how your data might work, you probably don't need a join at all, because your just using the join as a filter. So if that's the case, you can just do this, and just have one query.
select T.* from T
where #DoJoin = 0 or exists(SELECT * FROM L where L.col = T.col)
DECLARE #DoJoin BIT = 1
SELECT
T.*
FROM
T LEFT JOIN L ON T.col = L.col
WHERE
--Optional INNER/LEFT JOIN
(
--LEFT JOIN
#DoJoin = 0
OR
--INNER JOIN
(
-- only return rows from T where they have a record in L
#DoJoin = 1
AND
L.col IS NOT NULL
)
)

SQL Server select condition

I wanted to select count (*) from a table with condition based on type of one filed, consider below code I want something like this in one query:
select
count (*)
from
moniotr as m
case
when m.type = 1
begin
join paramter as p on p.id = m.paramId
where .....
end
when m.type = 2
begin
join aggTable as ag on ag.id = m.addId
where ....
Could you show me how to handle this in one query?
For more clearance, I want the count on monitors for those with type 1 with condition 1 and for type 2 with condition 2 , sum of those counts for two types!
thanks
do as 2 separate query and then union the result
select cnt = sum(cnt)
from
(
select cnt = count(*)
from monitor m
inner join paramter as p on p.id = m.paramId
where m.type = 1
union all
select cnt = count(*)
from monitor m
inner join aggTable as ag on ag.id = m.addId
where m.type = 2
) as d

Why IsNull it doesnt worK?

I'm trying to run this query and when it doesnt find value i need to take result 0.neither my return is null or empty.
select top(1)
ISNULL(CONVERT(DECIMAL(10,2),a.VatValue),0) as VatC
from VatCodes a
join
InventoryMainGroupItems b on a.VatcodeID = b.VatCodeID
join InventoryTransTemp c on c.CategoryID = b.MainGroupItemID
where
c.TrnDocumentID = '409'
and
a.VatcodeID = 3
Now my column returns emtpy.
My desired result should be 0
I could be wrong but I think the InventoryMainGroupItems has rows with a null in the VatCodeId column.
If this is the case then you can amend your slightly like so
select top(1)
ISNULL(CONVERT(DECIMAL(10,2),a.VatValue),0) as VatC
from InventoryMainGroupItems b
LEFT join
VatCodes a on a.VatcodeID = b.VatCodeID
INNER JOIN InventoryTransTemp c on c.CategoryID = b.MainGroupItemID
where
c.TrnDocumentID = '409'
and
a.VatcodeID = 3
There are at least 2 possibilities.
No rows meet the conditions as specified in the joins and where clause. Also, I'd start using explicit joins
The column VatValue doesnt' contain any NULL values, but instead contains empty spaces which isn't the same as NULL
Try to use replace to test for the empty string.
select top(1)
ISNULL(REPLCACE(CONVERT(DECIMAL(10,2),a.VatValue),'',0),0) as VatC
from VatCodes a
join
InventoryMainGroupItems b on a.VatcodeID = b.VatCodeID
join InventoryTransTemp c on c.CategoryID = b.MainGroupItemID
where
c.TrnDocumentID = '409'
and
a.VatcodeID = 3
If that doesn't work, your condition isn't returning any rows. Here's a way to prove that... this shouldn't return any rows....
select top(1)
a.VatValue as VatC
from VatCodes a
join
InventoryMainGroupItems b on a.VatcodeID = b.VatCodeID
join InventoryTransTemp c on c.CategoryID = b.MainGroupItemID
where
c.TrnDocumentID = '409'
and
a.VatcodeID = 3

How to use multiple values in between clause

Hi all is there any way that i can use multiple values in between clause as
column_name between 0 and 100 or 200 and 300 like this
Any help would be appreciated
here is my query SELECT CASE WHEN ISNUMERIC(value_text) = 1 THEN CAST(value_text AS INT) ELSE -1 END) between 0 and 100
i just want to append multiple values in between clause
This is full query
SELECT ROW_NUMBER() OVER
(
order by Vendor_PrimaryInfo.Vendor_ID asc
)AS RowNumber
, Unit_Table.Unit_title, Vendor_Base_Price.Base_Price, Vendor_Base_Price.showprice, Category_Table.Title, Vendor_Registration.Business_Name,
Vendor_PrimaryInfo.Street_Address, Vendor_PrimaryInfo.Locality, Vendor_PrimaryInfo.Nearest_Landmark, Vendor_PrimaryInfo.City, Vendor_PrimaryInfo.State,
Vendor_PrimaryInfo.Country, Vendor_PrimaryInfo.PostalCode, Vendor_PrimaryInfo.Latitude, Vendor_PrimaryInfo.Longitude, Vendor_PrimaryInfo.ImageUrl,
Vendor_PrimaryInfo.ContactNo, Vendor_PrimaryInfo.Email,Vendor_PrimaryInfo.Vendor_ID
FROM Unit_Table INNER JOIN
Vendor_Base_Price ON Unit_Table.Unit_ID = Vendor_Base_Price.Unit_ID INNER JOIN
Vendor_PrimaryInfo ON Vendor_Base_Price.Vendor_ID = Vendor_PrimaryInfo.Vendor_ID INNER JOIN
Vendor_Registration ON Vendor_Base_Price.Vendor_ID = Vendor_Registration.Vendor_ID AND
Vendor_PrimaryInfo.Vendor_ID = Vendor_Registration.Vendor_ID INNER JOIN
Category_Table ON Vendor_Registration.Category_ID = Category_Table.Category_ID
LEFT JOIN
Vendor_Value_Table ON Vendor_Registration.Vendor_ID = Vendor_Value_Table.Vendor_ID LEFT JOIN
Feature_Table ON Vendor_Value_Table.Feature_ID = Feature_Table.Feature_ID
where Vendor_Registration.Category_ID=5 and Vendor_PrimaryInfo.City='City'
AND(
value_text in('Dhol Wala$Shahnai Wala')
or
(SELECT CASE WHEN ISNUMERIC(value_text) = 1 THEN CAST(value_text AS INT) ELSE -1 END) between 0 and 100
)
You can do this using AND/OR logic
value_text NOT LIKE '%[^0-9]%' and
(
value_text between 0 and 100
Or
value_text between 101 and 200
)
If you don't want to repeat the column name then frame the range in table valued constructor and join with your table
SELECT Row_number()
OVER (
ORDER BY Vendor_PrimaryInfo.Vendor_ID ASC )AS RowNumber,
Unit_Table.Unit_title,
Vendor_Base_Price.Base_Price,
Vendor_Base_Price.showprice,
Category_Table.Title,
Vendor_Registration.Business_Name,
Vendor_PrimaryInfo.Street_Address,
Vendor_PrimaryInfo.Locality,
Vendor_PrimaryInfo.Nearest_Landmark,
Vendor_PrimaryInfo.City,
Vendor_PrimaryInfo.State,
Vendor_PrimaryInfo.Country,
Vendor_PrimaryInfo.PostalCode,
Vendor_PrimaryInfo.Latitude,
Vendor_PrimaryInfo.Longitude,
Vendor_PrimaryInfo.ImageUrl,
Vendor_PrimaryInfo.ContactNo,
Vendor_PrimaryInfo.Email,
Vendor_PrimaryInfo.Vendor_ID
FROM Unit_Table
INNER JOIN Vendor_Base_Price
ON Unit_Table.Unit_ID = Vendor_Base_Price.Unit_ID
INNER JOIN Vendor_PrimaryInfo
ON Vendor_Base_Price.Vendor_ID = Vendor_PrimaryInfo.Vendor_ID
INNER JOIN Vendor_Registration
ON Vendor_Base_Price.Vendor_ID = Vendor_Registration.Vendor_ID
AND Vendor_PrimaryInfo.Vendor_ID = Vendor_Registration.Vendor_ID
INNER JOIN Category_Table
ON Vendor_Registration.Category_ID = Category_Table.Category_ID
LEFT JOIN Vendor_Value_Table
ON Vendor_Registration.Vendor_ID = Vendor_Value_Table.Vendor_ID
LEFT JOIN Feature_Table
ON Vendor_Value_Table.Feature_ID = Feature_Table.Feature_ID
JOIN (VALUES (0, 100),
(101, 200),
(201, 300)) tc (st, ed)
ON Try_cast(value_text AS INT) BETWEEN st AND ed
OR Try_cast(value_text AS VARCHAR(100)) = 'Dhol Wala$Shahnai Wala'
WHERE Vendor_Registration.Category_ID = 5
AND Vendor_PrimaryInfo.City = 'City'
Note : You have stored two different information's in a single column which causes lot of pain when you want to extract the data like this. Consider changing your table structure

Count function returns empty record set need it to return 0 instead

I have this query...
SELECT COUNT(*) AS dupes
FROM documents d JOIN mv_compgift g ON g.documentId = d.id
JOIN mv_donorid di ON di.documentId = d.id
JOIN mv_appealcode ac ON ac.documentId = d.id
GROUP BY di.value,ac.value,d.dateDeleted
HAVING COUNT(*) > 1
AND g.value = 'Y'
AND d.dateDeleted IS NULL
AND di.value = '0621839010'
AND ac.value = 'AD62Q'
I need it to show a 0 when I have an empty record-set.
I have looked and tried different functions like coalesce but nothing works...please help. thanks
DECLARE #Count INT
SELECT #Count=COUNT(*) AS dupes
FROM documents d JOIN mv_compgift g ON g.documentId = d.id
JOIN mv_donorid di ON di.documentId = d.id
JOIN mv_appealcode ac ON ac.documentId = d.id
GROUP BY di.value,ac.value,d.dateDeleted
HAVING COUNT(*) > 1
AND g.value = 'Y'
AND d.dateDeleted IS NULL
AND di.value = '0621839010'
AND ac.value = 'AD62Q'
SELECT ISNULL(#Count,0) AS [dupes]
SELECT
COUNT(*), -- raw value
CASE COUNT(*)
WHEN 1 THEN 'OK' WHEN 0 THEN 'NOTHING' ELSE 'DUPS'
END as HasDups -- translated value
FROM documents d JOIN mv_compgift g ON g.documentId = d.id
JOIN mv_donorid di ON di.documentId = d.id
JOIN mv_appealcode ac ON ac.documentId = d.id
WHERE g.value = 'Y' AND d.dateDeleted IS NULL
AND di.value = '0621839010' AND ac.value = 'AD62Q'
Your HAVING condition was eliminating groups that didn't have dups. There was no way to ever get a zero back.
Also I'm surprised there wasn't an error on the g.value filter. All those conditions appear to belong in WHERE rather than HAVING anyway.

Resources