sql query updates all rows and not only where clause - sql

I am having trouble executing this query:
update public.fortune_companies
set industry_id = (select id
from public.industries
where name = 'Agriculture, Forestry and Fishing')
from Temp_Sic_Fortune_Companies as temp
left join public.fortune_companies as fc on fc.account_name = temp.account_name
where temp.sic between '0' and '499';
I think this is supposed to set the industry_id for only ones that have a sic number of 0-499 but it actually sets every record to the same id. No matter if the sic number is between 0-499 or not.
Why is this.

DECLARE #id INT;
SELECT #id = id
FROM public.industries
WHERE name = 'Agriculture, Forestry and Fishing';
UPDATE fc
SET industry_id = #id
FROM public.fortune_companies AS fc
WHERE EXISTS
(
SELECT 1
FROM dbo.Temp_Sic_Fortune_Companies
WHERE account_name = fc.account_name
AND sic BETWEEN '0' and '499'
);
Of course, if temp.sic = '3000', it will be part of the set. This is one of the dangers of using the wrong data type (or the wrong operator). You can fix that by saying:
AND sic BETWEEN '0' and '499'
AND LEN(sic) <= 3
Or by saying:
AND CASE WHEN ISNUMERIC(sic) = 1 THEN
CONVERT(INT, sic) ELSE -1 END BETWEEN 0 AND 499
(This avoids errors if - since you've let them - someone enters a non-numeric value into the column.)
Or by using the right data type in the first place.

Change the left join to inner join

Related

Update Column in table using Select, Inner Join and Case When

I have a table called: Claim, where I've already moved data from another table called Damage. However, today I needed to add a column in Claim called ClaimStatusID. And to give values to ClaimStatusID I need to to it based on another column called DamageApprovedStatusID, which exists in yet another table called DamageErrand. Damage and DamageErrand has relation through a crosstable called DamageErrandCrossDamage. In that crosstable DamageErrandID and DamageID exists. Here, I've commented more information:
-- Claim has column ID which has the same ID as the table Damage
-- DamageErrand has DamageApprovedStatus ID which need to be inserted
-- to ClaimStatusID, where the ID's need to be correct.
-- Table Damage and Table DamageErrand has a cross table:
-- DamageErrandCrossDamage, where both of their ID's are stored
-- Claim.ID should therefore be the same as DamageErrandCrossDamage.DamageID
-- Since Claim.ID has the same ID as Damage.ID
-- IF DamageApprovedStatus = -1, SET ClaimStatusID = 0
-- IF DamageApprovedStatus = 0, SET ClaimStatusID = 4
-- IF DamageApprovedStatus = 1, SET ClaimStatusID = 2
And here's a SQL query I created for selecting and using Case When to give the correct statuses:
SELECT Claim.ID as claimid, DamageErrandID as damageerrandeid,
CASE --
WHEN DamageErrand.DamageApprovedStatusID = -1 THEN 0
WHEN DamageErrand.DamageApprovedStatusID = 0 THEN 4
WHEN DamageErrand.DamageApprovedStatusID = 1 THEN 2
ELSE '-'
END AS DamageApprovedStatusID,
DamageApprovedStatusID
FROM
DamageErrand
INNER JOIN DamageErrandCrossDamage ON DamageErrand.ID =
DamageErrandCrossDamage.DamageErrandID
INNER JOIN Claim ON DamageErrandCrossDamage.DamageID = Claim.ID
WHERE Claim.ID = DamageErrandCrossDamage.DamageID
I do believe this is correct, with the ID's matching and everything. But how can I actually update the table Claim with this? I know insert won't work since I have columns that does not allow null in Claim table. I tried doing something similar to:
--UPDATE Claim
--SET ClaimStatusID =
--(SELECT DamageApprovedStatusID FROM
--DamageErrand
--INNER JOIN DamageErrandCrossDamage ON DamageErrand.ID =
-- DamageErrandCrossDamage.DamageErrandID
--INNER JOIN Claim ON DamageErrandCrossDamage.DamageID = Claim.ID
--WHERE Claim.ID = DamageErrandCrossDamage.DamageID)
But obviously this won't work either. Really thankful for any help!
Btw: I'm using SQL-server for this.
I believe something like this should work:
UPDATE Claim
SET ClaimStatusID = alias.DamageApprovedStatusID
FROM (
SELECT DamageErrandCrossDamage.DamageID,
CASE
WHEN DamageErrand.DamageApprovedStatusID = -1 THEN 0
WHEN DamageErrand.DamageApprovedStatusID = 0 THEN 4
WHEN DamageErrand.DamageApprovedStatusID = 1 THEN 2
ELSE '-'
END AS DamageApprovedStatusID
FROM DamageErrand
INNER JOIN DamageErrandCrossDamage ON DamageErrand.ID = DamageErrandCrossDamage.DamageErrandID
) alias
WHERE Claim.ID = alias.DamageID
I guess it could be rewritten like this too:
UPDATE Claim
SET ClaimStatusID = CASE
WHEN DamageErrand.DamageApprovedStatusID = -1 THEN 0
WHEN DamageErrand.DamageApprovedStatusID = 0 THEN 4
WHEN DamageErrand.DamageApprovedStatusID = 1 THEN 2
ELSE '-'
END
FROM DamageErrand
INNER JOIN DamageErrandCrossDamage ON DamageErrand.ID = DamageErrandCrossDamage.DamageErrandID
INNER JOIN Claim ON DamageErrandCrossDamage.DamageID = Claim.ID

How to refer to the exact object

I need a script that will change status to 0 for every student that has 3 or more absences
This is what I came up with:
UPDATE Group_cast
SET gc_Status = CASE WHEN ((SELECT COUNT(at_Presence)
FROM Attendance INNER JOIN Student ON at_stID = st_ID
INNER JOIN Group_cast ON st_ID = gc_stID
WHERE at_Presence = 0) >= 3) THEN 0
ELSE 1 END;
but it's updating every student status to 0 on the list and not just the one with 3 or more absences.
The problem is your subquery has a completely separate reference to Group_cast so it's counting a grand total for every Student, not just the one relevant to the row.
With no sample data, or expected results, this is impossible to test, but perhaps this?
UPDATE GC
SET gc_Status = CASE WHEN (SELECT COUNT(A.at_Presence) --Guessed the qualifier
FROM dbo.Attendance A
JOIN dbo.Student S ON A.at_stID = S.st_ID --Guessed the qualifiers
WHERE S.st_ID = GC.gc_stID --Guessed the qualifiers
AND A.at_Presence = 0) >= 3 THEN 0 --Guessed the qualifier
ELSE 1
END
FROM dbo.Group_cast GC;
Try this:
UPDATE Group_cast
set gc_Status =case when absentcnt>=3 then 0 end
from
(SELECT st_ID,COUNT(at_Presence) absentcnt
FROM Attendance INNER JOIN Student ON at_stID = st_ID
WHERE at_Presence = 0
group by st_ID)t where t.st_id=Group_cast.gc_stID

MSSQL 2012 - Why is AVG & TRY_CONVERT not returning the correct value?

I am using MSSQL 2012 and I am trying to use AVG together with TRY_CONVERT on a table column with the following datatype: nvarchar(255), NOT NULL
First before I try to query using AVG & TRY_CONVERT, this is the data that I want to get the AVG value out of using this query:
And this is the results after using AVG and TRY_CONVERT, 0 rows returned.
I also tried to use a subquery then i got 18 row returned, but with value NULL, i skipped out on AVG just to see if i was getting the correct values.. but it seems not, i also included the p.serialnumber column to show that its the correct rows that was returned, its just the value NULL that somehow appears after TRY_CONVERT.
UPDATE!:
When I execute the query below which target data that has a "." separator (qtv2.qtv_qteid = 58 (instead of 63)) , it works! So the issue is the "," separator. Anyone know solution to this??
declare #ProjectSelection nvarchar(10)
set #ProjectSelection = 'C82007588'
SELECT AVG(TRY_CONVERT(numeric(10,5), avgcap))
FROM
(
select qtv2.qtv_result as avgcap
from ProductionOrder PO
left join CustomerOrder co on co.CustomerOrderId=po.customerorderid
left join ProductionOrderProperty pop on pop.ProductionOrderId=po.productionorderid
left join product p on p.ProductionOrderId=po.productionorderid
left join QualityTestValues qtv on qtv.qtv_productid=p.ProductId
left join QualityTestValues qtv2 on qtv2.qtv_productId=p.ProductId
where pop.Value=#ProjectSelection and pop.name = 'project' and po.ProductTypeId = 1
and qtv2.qtv_qteid = 58 and qtv2.qtv_valid = 1 and qtv.qtv_ProductSegmentId = 144 and qtv.qtv_valid = 1
and qtv.qtv_qteid = 51 and qtv.qtv_result = 'J'
group by co.CustomerName, pop.Value, qtv2.qtv_result, p.SerialNumber
) A
Result:
(No column name)
22.200000
How about your compatibility level? A similar question can be found here:
TRY_CONVERT fails on SQL Server 2012
Although your server version is 2012, a lower compatibility level can cause the try_convert to be unavailable for use in your database. You can check this by running the following code in your specific database and afterwards on for instance the master database.
DECLARE #b VARCHAR(10) = '12312'
SELECT TRY_CONVERT(INT,#b)
You can take your first query and do something like this:
SELECT AVG(TRY_CONVERT(numeric(10,5), avgcap))
FROM
(
-- Insert your first query here.
) A
This should give you the average of the numbers.
EDIT
Here is a workable example that should return 24.000000.
SELECT AVG(TRY_CONVERT(numeric(10,5), A))
FROM
(
SELECT '22.5' AS A
UNION
SELECT '23.5' AS A
UNION
SELECT '26.0' AS A
) B
I found out the solution, using TRY_PARSE instead of TRY_CONVERT.
DECLARE #ProjectSelection nvarchar(10)
SET #ProjectSelection = 'C82007588'
SELECT AVG(avgcap) as avgcap
FROM
(
SELECT qtv2.qtv_result, TRY_PARSE( qtv2.qtv_result AS NUMERIC(10,3)) avgcap
FROM ProductionOrder PO
LEFT JOIN CustomerOrder co on co.CustomerOrderId=po.customerorderid
LEFT JOIN ProductionOrderProperty pop on pop.ProductionOrderId=po.productionorderid
LEFT JOIN product p on p.ProductionOrderId=po.productionorderid
LEFT JOIN QualityTestValues qtv on qtv.qtv_productid=p.ProductId
LEFT JOIN QualityTestValues qtv2 on qtv2.qtv_productId=p.ProductId
WHERE pop.Value=#ProjectSelection
AND pop.name = 'project'
AND po.ProductTypeId = 1
AND qtv2.qtv_qteid = 63
AND qtv2.qtv_valid = 1
AND qtv.qtv_ProductSegmentId = 144
AND qtv.qtv_valid = 1
AND qtv.qtv_qteid = 51
AND qtv.qtv_result = 'J'
GROUP BY co.CustomerName, pop.Value, qtv2.qtv_result, p.SerialNumber
) A`
Results:
avgcap
21264.850000

Literal vs variable in T-SQL query with view produces vastly different query time

When I use a literal in a WHERE clause in a query against a view, the result is basically instantaneous. When I use a variable set to that same value, a completely different and very slow query plan takes its place. How is this possible? How can these be vastly different:
DECLARE #a INT = 5
SELECT ...
WHERE myview.mycol = #a
vs
SELECT ...
WHERE myview.mycol = 5
Here is the exact query and timing that I am encountering (I can post additional information about the view itself, but I don't know that posting the view definition itself is that useful: it is complex and relies on a dozen other views and tables. I can post it if it's helpful in answering the question.)
DECLARE #productdbuid INT = 5
DECLARE #t1 DATETIME;
DECLARE #t2 DATETIME;
---------------------
SET #t1 = GETDATE();
SELECT
*
FROM
vwPublishingActions
WHERE
productdbuid = 5 AND storedbuid = 1
SET #t2 = GETDATE();
SELECT DATEDIFF(MILLISECOND,#t1,#t2) time1;
---------------------
SET #t1 = GETDATE();
SELECT
*
FROM
vwPublishingActions
WHERE
productdbuid = #productdbuid AND storedbuid = 1
SET #t2 = GETDATE();
SELECT DATEDIFF(MILLISECOND,#t1,#t2) time2;
time1: 13
time2: 2796
What is causing SQL Server to treat the literal 5 so differently from #productbuid INT = 5?
Thanks so much for any guidance.
UPDATE: I've been asked to include the view definition:
SELECT
T2.productdbuid,
T2.storedbuid,
ISNULL(paca.publishactiondbuid, 8) publishingaction, -- 8 = ERROR_REPORT
T2.change_product,
T2.change_price,
T2.change_stockstatus,
T2.inventory_belowtrigger,
T2.ruledbuid ruledbuid
FROM
(SELECT
T.productdbuid,
T.storedbuid,
-- pick first fully matching set of conditions
(SELECT TOP 1 paca.dbuid
FROM dbo.z_PublishingActionCalcs paca
WHERE (paca.storetypedbuid = T.storetypedbuid)
AND (paca.publishingcommanddbuid = T.publishcommanddbuid OR paca.publishingcommanddbuid IS NULL)
AND (ISNULL(paca.publishingstatusdbuid, 0) = ISNULL(T.publishstatusdbuid, 1007) OR paca.publishingstatusdbuid IS NULL) -- 1007 = NOTSET
AND (ISNULL(ABS(paca.change_product),0) = ISNULL(ABS(T.change_product),0) OR paca.change_product IS NULL)
AND (ISNULL(ABS(paca.change_price),0) = ISNULL(ABS(T.change_price),0) OR paca.change_price IS NULL)
AND (ISNULL(ABS(paca.change_stockstatus),0) = ISNULL(ABS(T.change_stockstatus),0) OR paca.change_stockstatus IS NULL)
AND (ISNULL(ABS(paca.inventory_belowtrigger),0) = ISNULL(ABS(T.inventory_belowtrigger),0) OR paca.inventory_belowtrigger IS NULL)
AND (ISNULL(paca.stockstatusdbuid, 0) = ISNULL(T.stockstatusdbuid, 0) OR paca.stockstatusdbuid IS NULL)
ORDER BY paca.sort) ruledbuid,
ABS(ISNULL(T.change_product,0)) change_product,
ABS(ISNULL(T.change_price,0)) change_price,
ABS(ISNULL(T.change_stockstatus,0)) change_stockstatus,
ABS(ISNULL(T.inventory_belowtrigger,0)) inventory_belowtrigger
FROM
(SELECT
p.productid,
s.storetypedbuid,
CASE
WHEN pdpcm.publishcommanddbuid <> 4
THEN NULL -- STOCKSTATUS
ELSE pss.stockstatusdbuid
END product_stockstatus,
CASE
WHEN pdpcm.publishcommanddbuid <> 5
THEN NULL -- INVENTORY
ELSE itr.inventory_belowtrigger
END inventory_belowtrigger,
p.dbuid productdbuid,
s.dbuid storedbuid,
pdpc.change_product,
pdpc.change_price,
pdpc.change_stockstatus,
pdpcm.publishcommanddbuid,
pdps.publishstatusdbuid,
pss.stockstatusdbuid
FROM
dbo.ProductDetailsPublishingCommands pdpcm
INNER JOIN
dbo.Stores s ON s.dbuid = pdpcm.storedbuid
INNER JOIN
dbo.Products p ON pdpcm.productdbuid = p.dbuid
INNER JOIN
dbo.StoreTypeSet st ON st.dbuid = s.storetypedbuid
LEFT JOIN
dbo.vwPublishingChanges pdpc ON pdpc.productdbuid = p.dbuid
AND pdpc.storedbuid = s.dbuid
LEFT JOIN
dbo.ProductDetailsPublishingStatuses pdps ON pdps.productdbuid = p.dbuid
AND pdps.storedbuid = s.dbuid
LEFT JOIN
dbo.vwProductStockStatus pss ON pss.productdbuid = p.dbuid
LEFT JOIN
dbo.vwProductInventory pri ON pri.productdbuid = p.dbuid
LEFT JOIN
dbo.vwInventoryTriggers itr ON itr.storedbuid = s.dbuid
AND itr.productdbuid = p.dbuid) T
) T2
LEFT JOIN
dbo.z_PublishingActionCalcs paca ON T2.ruledbuid = paca.dbuid
You would need to look at the execution plan to be sure.
When you use a variable mycol = #a SQL Server will create a plan based on average column density for values in mycol.
The mycol = 5 predicate may be significantly above or below the average. When you use a literal SQL Server can lookup the value 5 in the column statistics and potentially get more accurate estimates and thus a more appropriate plan.
Additionally using a literal can allow some additional optimisations and simplifications.
An example is that a view with a PARTITION BY mycol can have the literal predicate pushed further down than a variable or parameter generally can (except when using OPTION (RECOMPILE)).
Additionally with the literal value available at compilation SQL Server may be able to simplify expressions and use contradiction detection to eliminate some of the work at run time.

SQL Server:An expression of non-boolean type specified in a context where a condition is expected

I apologize I'm asking this question when this specific error type has already been asked multiple times before, but I've looked through them and am not explicitly seeing my answer.
I am trying to build a trigger that takes records inserted into a table (FDC_Trip_History), selects some information from the record, joins on other tables to pull additional data, etc. and inserts a record into another table (Staging).
I'm getting this error at the bottom of my script, the 4th line from the end after the FROM section. Any idea why?
CREATE TRIGGER Insert_Trip_History ON FDC_Trip_History
AFTER INSERT
AS BEGIN
SET NOCOUNT ON;
--If inserted record reaches a certain 'status' of archive then continue
If EXISTS (SELECT * FROM inserted WHERE inserted.description like '%archive%')
BEGIN
--If inserted record can be 'billed', and hasn't already been processed, then continue.
IF EXISTS ( SELECT * FROM inserted
INNER JOIN FDC_Trips on inserted.tdate = FDC_Trips.tdate and inserted.job = FDC_Trips.job and inserted.SourceDB = FDC_trips.sourceDB
INNER JOIN AMS.dbo.Billable_Outcome_Filter as eBill on FDC_trips.SourceDB = eBill.SourceDB and FDC_Trips.outcome = eBill.Outcome_Code)
AND NOT EXISTS ( SELECT * FROM inserted
INNER JOIN Staging as Stg on inserted.tdate = Stg.tdate and inserted.job = Stg.job and inserted.sourcedb = Stg.sourceDB)
BEGIN
INSERT INTO Staging
(EVENT_OPERATION,
EVENT_SOURCE_TABLE,
EVENT_PRIORITY,
EVENT_TIME_UPDATED,
EVENT_STATUS,
EVENT_COMMENT,
TDATE,
JOB,
SOURCEDB,
CUSTNO,
SHIFTNO,
TYPE,
PROFITCENTER,
BILLINGRATEPROFITCENTER)
SELECT
'CREATE' as [EVENT_OPERATION],
'FDC_Trip_History' as [EVENT_SOURCE_TABLE],
'1' as [EVENT_PRIORITY],
GETDATE() as [EVENT_TIME_ADDED],
null as [EVENT_TIME_UPDATED],
'0' as [EVENT_STATUS],
'' as [EVENT_COMMENT],
eTHistory.tdate as [TDATE],
eTHistory.job as [JOB],
eTHistory.sourcedb as [SOURCEDB],
eT.custno as [CUSTNO],
eT.shiftno as [SHIFTNO],
'Completed' as [TYPE],
--Decide Profit Center. Profit center (PC) determined from dispatch zone (Trips.dzone)
CASE
WHEN cType.descr LIKE 'ATS%'
THEN DispatchZone.ATS_ProfitCenter
ELSE DispatchZone.ProfitCenter
END,
--Decide Billing rate profit center. Billing rate profit center (BRPC) determined from pickup zone. Does ATS logic apply to BRPC too?
CASE
WHEN cType.descr LIKE 'ATS%'
THEN PickupZone.ATS_ProfitCenter
ELSE PickupZone.ProfitCenter
END
as [BILLINGRATEPROFITCENTER]
FROM inserted
INNER JOIN FDC_Trip_History as eTHistory
INNER JOIN FDC_Trips as eT on eTHistory.tdate = eT.tdate and eTHistory.job = eT.job and eTHistory.sourcedb = eT.sourcedb
LEFT JOIN Trips as T on T.tdate = eTHistory.tdate and T.sourcedb = eTHistory.sourceDB and T.Job = eTHistory.Job
LEFT JOIN Call_Types as cType on cType.code = eT.calltype and cType.sourceDB = eT.sourceDB
LEFT JOIN Zones as DispatchZone on DispatchZone.code = T.dzone
LEFT JOIN Zones as PickupZone on PickupZone.code = eT.puzone /* Error pops up right here */
END
END
END
You seem to have forgotton the specify the join criteria for the FDC_Trip_History table (the first INNER JOIN).
In addition, you have 14 columns in your INSERT list but 15 in your SELECT statement.