i have the following statement in a stored procedure that is returning strange results. Given two columns where one (RL) is less than 0 e.g -2, it should add 2 to another column (HD). If the negative value was -8 it should add 8 to the HD column.
In a test ive just done, the RL column had 0 and HD was 2. I changed the RL to -2 and run the code. I was EXPECTING : RL = 0 and HD = 4. INSTEAD the RESULT was RL = 0 and HD = 5.
I think the problem is due to the presence of the join. How would i write this to replace the join with a WHERE clause please.
UPDATE P
SET P.HD = P.HD + P.RL
,P.RL = 0
FROM Products P
INNER JOIN (
SELECT id
,RL
FROM Products
WHERE id IN (
SELECT ProductID
FROM OrderDetails
WHERE OrderID = #OrderId
)
AND RL < 0
) Q ON P.ID = Q.id
cheers
Try this one -
UPDATE Products
SET HD = HD + RL,
RL = 0
FROM P
WHERE RL < 0
AND ID IN (
SELECT ProductID
FROM dbo.OrderDetails
WHERE OrderID = #OrderId
)
Small check -
DECLARE #t TABLE (a INT, b INT)
INSERT INTO #t (a, b)
VALUES (1, 2)
UPDATE #t
SET a = b, b = 0
SELECT * FROM #t
Related
I have a stored proc where a table of integers is passed as a parameter. I'm trying to find a reasonable way of writing "give me all the records, but if the parameter table has values in it then limit my results to those values".
Both approaches in the queries below work, but when I use either approach in my real-world proc (with a substantial number of joins and apply clauses and a ton of data) it's quite a bit slower than I would like even when the number of rows in the variable table is limited to 1 or 2 records.
Is there a better way of doing this?
-- Apprroach1 - Weird WHERE clause
IF OBJECT_ID('tempdb.dbo.#list') IS NOT NULL DROP TABLE #list
create table #list(Id int)
insert into #list(id) values (726), (712), (725)
declare #listCount int
select #listCount = count(*) from #list
select * from SalesLT.Product p
where 1 = 1
AND
(
#listCount > 0 AND p.ProductID in (select Id from #list)
OR
#listCount = 0
)
and
-- approach 2 - goofy looking JOIN
IF OBJECT_ID('tempdb.dbo.#list') IS NOT NULL DROP TABLE #list
create table #list(Id int)
insert into #list(id) values (726), (712), (725)
declare #listCount int
select #listCount = count(*) from #list
select * from SalesLT.Product p
inner join #list l on
case when #listCount > 0 and l.Id = p.ProductID Then 1
else 0
end = 1
Generally, case when in joins (ON clause) are avoided as it will make less performant query.
Use the left join approach as follows:
select * from SalesLT.Product p
Left join #list l on l.Id = p.ProductID
Where ( (#listCount > 0 and l.id is not null)
or #listCount = 0)
Try this
IF #listCount > 0
BEGIN
SELECT
*
FROM SalesLT.Product p
------------------------
INNER JOIN #list l ON
------------------------
l.Id = p.ProductID
------------------------
END
-- I assume you want to output everything if #listCount = 0
ELSE IF #listCount = 0
BEGIN
SELECT
*
FROM SalesLT.Product p
END
If you have a bunch of joins using that table outputs, you can store the output and use it on your real join/query.
Example:
IF #listCount > 0
BEGIN
SELECT
*
INTO #TempSalesTbl
FROM SalesLT.Product p
------------------------
INNER JOIN #list l ON
------------------------
l.Id = p.ProductID
------------------------
END
-- In your query
SELECT
*
FROM Table A
INNER JOIN #TempSalesTbl ON
...
I have some variable set that could look something like this:
SET #ItemID1 = 3
SET #ItemID2 = 26
SET #ItemID3 = NULL
SET #ItemRadius1 = 5000
SET #ItemRadius2 = 5000
SET #ItemRadius3 = NULL
The ItemID is a lookup field and the radius is distance in meters. eg The query should return all Assets within 5000 meters of items with the ID of #ItemID1.
My query is currently joining on if the distance between the "Geo" field (which is a geography type) is less than whatever the radius is entetered.
SELECT DISTINCT
a.AssetID,
a.Name
FROM Asset a
JOIN Item i1 ON ((a.Geo.STDistance(i1.Geo) < #ItemRadius1) AND i1.TypeID = #ItemID1)
JOIN Item i2 ON ((a.Geo.STDistance(i2.Geo) < #ItemRadius2) AND i2.TypeID = #ItemID2)
JOIN Item i3 ON ((a.Geo.STDistance(i3.Geo) < #ItemRadius3) AND i3.TypeID = #ItemID3)
My issue is that this is being set up as a procedure and the declared variables may be null. If they are my query will return no results. Is there a way to run the condition only if #ItemID3 IS NOT NULL AND #ItemRadius3 IS NOT NULL. I have tried selecting my results into a declared table then running the join on that declared table but my results were not filtering correctly. Any suggestions would be appreciated.
I would suggest writing the query as:
SELECT a.*
FROM Asset a
WHERE (#ItemID1 IS NULL OR ItemRadius1 IS NULL OR
EXISTS (SELECT 1
FROM Item i1
WHERE a.Geo.STDistance(i1.Geo) < #ItemRadius1 AND i1.TypeID = #ItemID1)
) AND
(#ItemID2 IS NULL OR ItemRadius2 IS NULL OR
EXISTS (SELECT 1
FROM Item i2
WHERE a.Geo.STDistance(i2.Geo) < #ItemRadius2 AND i2.TypeID = #ItemID1)
) AND
(#ItemID3 IS NULL OR ItemRadius3 IS NULL OR
EXISTS (SELECT 1
FROM Item i3
WHERE a.Geo.STDistance(i3.Geo) < #ItemRadius3 AND i3.TypeID = #ItemID1)
) ;
At the very least, this eliminates the overhead for the SELECT DISTINCT.
I have two tables:
devices : (id (int), type(int))
devices_log : (id (int), device_id (int) (FK), data(string), date(string))
The type is a number between 1 and 10, the data column should be a number between 1 and 100 ("1", ..., "100") or "emptyX" (the X represents any character from "a" to "z")
The device which has the type 9 always has a number in the data column.
I need to update the data field for all the "type 9" devices which
have a data bigger than 50 so that ==> data = data /2.
I've started with an INNER JOIN :
select l.id
from devices_log l
inner join (select id from devices where type = 9) d on (l.device_id = d.id)
This statement returns all the logs for "type 9" devices, but when I add the where condition :
select l.id
from devices_log l
inner join (select id from devices where type = 9) d on (l.device_id = d.id)
where cast(data as INTEGER) > 50
I got this error :
ERROR: invalid input syntax for integer: "emptyG"
I've also tried so many statements that lead to the same error :
select id
from devices_log
where device_id in (select id from devices where type = 9)
and cast(data as integer) > 50
select id from
(
select id, device_id, cast (devices_log.data as integer) as int_data
from devices_log
join devices on (devices_log.device_id = devices.id
) and type = 9) ccs where ccs.int_data > 50
Any suggestions?
Thanks in advance
SQL queries describe the result set, not the specific steps being taken. I actually thought this problem didn't appear in Postgres (I've seen it in other databases). I would start with this version:
select l.id
from devices_log l inner join
devices d
on l.device_id = d.id
where d.type = 9 and cast(l.data as INTEGER) > 50 ;
If this doesn't fix the problem, then you can fix this with a case in the where:
select l.id
from devices_log l inner join
devices d
on l.device_id = d.id
where d.type = 9 and
(case when d.type = 9 then cast(l.data as INTEGER) end) > 50 ;
The case should not evaluate the then unless the condition is true.
I have a select query returning two results and what I want is to save them in a table type of variable. This is how I am doing it:
declare #CompletedTotalValues table (CMedian int, CPerc int);
update #CompletedTotalValues set CMedian = t.CMed, CPercentile = t.CPerc
from(
Select CMed = dbo.median(case when cr.Priority = 1 then cr.Days else null end),
CPerc = dbo.Percentile90(case when cr.Priority = 1 then cr.Days else null end)
from A a inner join B b on b.Id = a.Id
where b.StatusId = 3
) t;
Here, when I run the subquery, I see CMed is 25 and CPerc is 43. However, when I execute Select * from #CompletedTotalValues, it is returning both column blank (no value it shows). Where is my mistake? Any advice would be appreciated
Why not just insert the data in the first place?
DECLARE #CompletedTotalValues TABLE (CMedian INT, CPerc INT);
INSERT #CompletedTotalValues (CMedian, CPerc)
SELECT CMed = dbo.median(CASE WHEN cr.Priority = 1 THEN cr.Days END),
CPerc = dbo.Percentile90(CASE WHENn cr.Priority = 1 THEN cr.Days END)
FROM A
INNER JOIN B ON b.Id = a.Id
WHERE b.StatusId = 3;
If I go by the query you have shared, you are trying to update without even inserting any data in the table variable at first place. Is it?
Trying to optimize a query it is updaing the records in table A based on the INTERSECT on two data sets.
UPDATE #TableA
SET IsFlag = CASE WHEN ISNULL(RJobFlag, 0) > 0 THEN 0 ELSE 1 END
FROM #TableA AS ABC
OUTER APPLY (
SELECT 1 RJobFlag
WHERE EXISTS (
SELECT ABC.COLUMN1,ABC.COLUMN2,ABC.COLUMN3,ABC.COLUMN4,ABC.COLUMN5,ABC.COLUMN6,ABC.COLUMN7,ABC.COLUMN8,ABC.COLUMN8,ABC.COLUMN9,ABC.COLUMN10,StudentID,SubjectID
INTERSECT
SELECT XYZ.COLUMN1,XYZ.COLUMN2,XYZ.COLUMN3,XYZ.COLUMN4,XYZ.COLUMN5,XYZ.COLUMN6,XYZ.COLUMN7,XYZ.COLUMN8,XYZ.COLUMN8,XYZ.COLUMN9,XYZ.COLUMN10,StudentID,SubjectID
FROM #TableB AS XYZ
WHERE XYZ.COLUMN1 = (SELECT DISTINCT ID FROM #TableC MNOP WHERE MNOP.StudentID = ABC.StudentID)
AND StudentID = ABC.StudentID
AND SubjectID = ABC.SubjectID )
) Subquery
WHERE ABC.COLUMN1= '2'
Appretiated if you have some ideas to better optimize it.
Thanks
This might be worse never know.
UPDATE tA
SET IsFlag = COALESCE(RJobFlag, 0)
FROM #TableA tA
LEFT JOIN ( SELECT 1 RJobFlag, *
FROM #TableB tB
WHERE EXISTS ( SELECT *
FROM #TableC tC
WHERE tC.ID = tB.COLUMN1 AND tC.StudentID = tB.StudentID)
) tB
ON tA.StudentID = tB.StudentID
AND tA.SubjectID = tB.SubjectID
AND tA.COLUMN1 = tB.COLUMN1
AND tA.COLUMN2 = tB.COLUMN2
AND tA.COLUMN3 = tB.COLUMN3
AND tA.COLUMN4 = tB.COLUMN4
AND tA.COLUMN5 = tB.COLUMN5
AND tA.COLUMN6 = tB.COLUMN6
AND tA.COLUMN7 = tB.COLUMN7
AND tA.COLUMN8 = tB.COLUMN8
AND tA.COLUMN9 = tB.COLUMN9
AND tA.COLUMN10 = tB.COLUMN10
If #TableA has a bunch of records and you're using outer apply or outer join every time you update it will be slow since it has to update every single record. maybe there's a way to only update the records that have changed?