SQL: Using case to change column value on 1 row only where value exists on 2 rows - sql

I have a dataset that looks like so:
You'll notice that the Text column has two rows with the same value; PERCENT ACHIEVED. I want to change the Text value on row 2, to PERCENT ACHIEVED MONTH and keep row 5 as-is.
Using a case statement changes both rows. How do I change the value of just one row using SQL only?
I am using SQL Server 2016.
Current SQL to generate the dataset, looks like so
SELECT
DimCompany.SID as CompanyFK,
DimBrand.SID as BrandFK,
DimSalesman.SID as SalesmanFK,
FLD01A as [Text],
FLD024 as [Value]
FROM OPENQUERY(SYSTEM21,'
select
*
from CWAUL.SA080VMF
')
LEFT JOIN DimCompany ON DimCompany.CompanyCode = 'CW'
LEFT JOIN DimBrand ON DimBrand.BrandName = 'Group'
LEFT JOIN DimSalesman ON DimSalesman.SalesmanCode = 'R11'

Related

How to replace a value in one field by a value from another field (different column) within the same view table (SQL)?

I'd like to know if it is possible to replace a value from one field by using a value from another column and a different row.
For Example, click this to view the table image.
I'd like the SumRedeemed value 400 in row 15 to be replaced by the value -1*(-395); the value -395 comes from the EarnPointsLeft in row 6 (both have the same CID meaning that they are the same person). Any suggestions?
You need this update statement:
update t
set t.sumredeemed = (-1) * (select earnpointsleft from FifoPtsView where cid = t.cid)
from FifoPtsView t
where t.cid = 5000100008 and t.earnpointsleft = 0
This will work if the select statement will return only 1 row.
you can simply update your table
update t
set t.sumredeemed = ABS(t2.earnpointsleft )
from FifoPtsView t join FifoPtsView t2 on t.cid = t.cid and isnull(t2.earnpointsleft,0)>0
if you want negative values you can remove ABS ,
please give me your feedbacks

Access query inconsistently treats empty string as null

I have an application that is grabbing data from an Access database. I am seeking the minimum value of a column and the results I am getting back are inconsistent.
Have I run into a feature where Access inconsistently treating an empty string as a null depending on whether I add a filter or not, or is there something wrong with the way I am querying the data?
The column contains one blank value (not null) and several non-blank values that are all identical (about 30 instances of 'QLD'). The query I am using has a filter that involves multiple other tables, so that only the blank value and about half of the 'QLD' values are eligible.
It's probably easier to show the code and the effects rather than describe it. I have created a series of unioned queries which 'should' bring back identical results but do not.
Query:
SELECT 'min(LOC_STATE)' as Category
, min(LOC_STATE) as Result
FROM pay_run, pay_run_employee, employee, department, location
WHERE pr_id = pre_prid
AND em_location = loc_id
AND pre_empnum = em_empnum
AND em_department = dm_id
AND pr_date >= #2/24/2015#
AND pr_date <= #2/24/2016#
UNION ALL
(SELECT TOP 1 'top 1 LOC_STATE'
, LOC_STATE
FROM pay_run, pay_run_employee, employee, department, location
WHERE pr_id = pre_prid
AND em_location = loc_id
AND pre_empnum = em_empnum
AND em_department = dm_id
AND pr_date >= #2/24/2015#
AND pr_date <= #2/24/2016#
ORDER BY LOC_STATE)
UNION ALL
SELECT 'min unfiltered', min(loc_state)
FROM location
UNION ALL
(SELECT TOP 1 'iif is null', iif(loc_state is null, 'a', loc_state)
FROM location
ORDER BY loc_state)
Results:
Category Result
min(LOC_STATE) 'QLD'
top 1 LOC_STATE ''
min unfiltered ''
iif is null ''
If I do a minimum with the filter it brings back 'QLD' and not the empty string. At this stage it is possible that the empty string is not being included because it is treated as a null or the filter removes it.
The second query, which brings back the top 1 state using the filter shows that the empty string is not filtered out, which means that the Min function is ignoring the empty string.
The third query, which gets the minimum of the unfiltered table, brings back the empty string - so the minimum function does not exclude empty strings / treat them as null.
The fourth query, ensures that there is not a null in the empty string position.
My conclusion is that perhaps the inclusion of other tables and filter criteria is causing the empty string value to be treated as a null, but I feel that I must be missing something.
NB: I have a very similar query (date literals altered) that executes against the same data imported into a SQL Server database. It is correctly returning '' for all 4 queries.
Does anyone know why the empty string is ignored by the Min function in the first query?
PS: for those who prefer a query with joins
SELECT 'min(LOC_STATE)' as Category
, min(LOC_STATE) as Result
FROM (((pay_run
INNER JOIN pay_run_employee ON pay_run.pr_id = pay_run_employee.pre_prid)
INNER JOIN employee ON pay_run_employee.pre_empnum = employee.em_empnum)
INNER JOIN department ON employee.em_department = department.dm_id)
INNER JOIN location on employee.em_location = location.loc_id
WHERE
PR_DATE >= #2/24/2015# and
PR_DATE <= #2/24/2016#
union all
(SELECT TOP 1 'TOP 1 LOC_STATE'
, LOC_STATE
FROM (((pay_run
INNER JOIN pay_run_employee ON pay_run.pr_id = pay_run_employee.pre_prid)
INNER JOIN employee ON pay_run_employee.pre_empnum = employee.em_empnum)
INNER JOIN department ON employee.em_department = department.dm_id)
INNER JOIN location on employee.em_location = location.loc_id
WHERE
PR_DATE >= #2/24/2015# and
PR_DATE <= #2/24/2016#
order by LOC_STATE)
union all
select 'min unfiltered', min(loc_state)
from location
This has got nothing to do with corrupt data or unions or joins. The problem can be easily made visible by exectuting following queries in access:
create table testbug (Field1 varchar (255) NULL)
insert into testbug (Field1) values ('a')
insert into testbug (Field1) values ('')
insert into testbug (Field1) values ('c')
select min(field1) from testbug
To my opinion this is a bug in ms-access. When the MIN function in ms-access comes across an empty string ('') it forgets all the values he has come across and returns the minimum value from all the values below the empty string. (in my simple example only value 'c')

How do I add a conditional column to a union query in MS SQL?

In MS SQL is there a way I can add a conditional column to a union query like the one below based on the value of the first column?
basically im trying to add the bin value as a fourth column if the part value is like ('%XX') or have it display 0, so far I have only been able to add another column which mirrors the MAX(part_bins.bin) column if the code doesn't meet the like.
SELECT part_bins.part AS part,
SUM(part_bins.free_stock) AS FREE_STOCK,
MAX(PART_BINS.BIN) AS Bin
FROM part_bins
LEFT OUTER JOIN part ON part_bins.part = part.part
WHERE (part_bins.free_stock > 0)
GROUP BY part_bins.part
UNION
SELECT part.master_part AS part,
SUM(part_bins.free_stock) AS FREE_STOCK,
MAX(PART_BINS.BIN) AS Bin
FROM part_bins
LEFT OUTER JOIN part ON part_bins.part = part.part
WHERE (part_bins.free_stock > 0)
GROUP BY part.master_part
You can use a CASE statement and you have to add it in both queries to add the fourth column like;
--4th Column for both queries, if bin_value is a numeric type
case when part_value like '%XX' then bin_value
else 0 end as fourth_column
--4th Column for both queries, if bin_value is a string type
case when part_value like '%XX' then bin_value
else '0' end as fourth_column

Help with a complex join query

Keep in mind I am using SQL 2000
I have two tables.
tblAutoPolicyList contains a field called PolicyIDList.
tblLossClaims contains two fields called LossPolicyID & PolicyReview.
I am writing a stored proc that will get the distinct PolicyID from PolicyIDList field, and loop through LossPolicyID field (if match is found, set PolicyReview to 'Y').
Sample table layout:
PolicyIDList LossPolicyID
9651XVB19 5021WWA85, 4421WWA20, 3314WWA31, 1121WAW11, 2221WLL99 Y
5021WWA85 3326WAC35, 1221AXA10, 9863AAA44, 5541RTY33, 9651XVB19 Y
0151ZVB19 4004WMN63, 1001WGA42, 8587ABA56, 8541RWW12, 9329KKB08 N
How would I go about writing the stored proc (looking for logic more than syntax)?
Keep in mind I am using SQL 2000.
Select LossPolicyID, * from tableName where charindex('PolicyID',LossPolicyID,1)>0
Basically, the idea is this:
'Unroll' tblLossClaims and return two columns: a tblLossClaims key (you didn't mention any, so I guess it's going to be LossPolicyID) and Item = a single item from LossPolicyID.
Find matches of unrolled.Item in tblAutoPolicyList.PolicyIDList.
Find matches of distinct matched.LossPolicyID in tblLossClaims.LossPolicyID.
Update tblLossClaims.PolicyReview accordingly.
The main UPDATE can look like this:
UPDATE claims
SET PolicyReview = 'Y'
FROM tblLossClaims claims
JOIN (
SELECT DISTINCT unrolled.LossPolicyID
FROM (
SELECT LossPolicyID, Item = itemof(LossPolicyID)
FROM unrolling_join
) unrolled
JOIN tblAutoPolicyList
ON unrolled.ID = tblAutoPolicyList.PolicyIDList
) matched
ON matched.LossPolicyID = claims.LossPolicyID
You can take advantage of the fixed item width and the fixed list format and thus easily split LossPolicyID without a UDF. I can see this done with the help of a number table and SUBSTRING(). unrolling_join in the above query is actually tblLossClaims joined with the number table.
Here's the definition of unrolled 'zoomed in':
...
(
SELECT LossPolicyID,
Item = SUBSTRING(LossPolicyID,
(v.number - 1) * #ItemLength + 1,
#ItemLength)
FROM tblLossClaims c
JOIN master..spt_values v ON v.type = 'P'
AND v.number BETWEEN 1 AND (LEN(c.LossPolicyID) + 2) / (#ItemLength + 2)
) unrolled
...
master..spt_values is a system table that is used here as the number table. Filter v.type = 'P' gives us a rowset with number values from 0 to 2047, which is narrowed down to the list of numbers from 1 to the number of items in LossPolicyID. Eventually v.number serves as an array index and is used to cut out single items.
#ItemLength is of course simply LEN(tblAutoPolicyList.PolicyIDList). I would probably also declared #ItemLength2 = #ItemLength + 2 so it wasn't calculated every time when applying the filter.
Basically, that's it, if I haven't missed anything.
If the PolicyIDList field is a delimited list, you have to first separate the individual policy IDs and create a temporary table with all of the results. Next up, use an update query on the tblLossClaims with 'where exists (select * from #temptable tt where tt.PolicyID = LossPolicyID).
Depending on the size of the table/data, you might wish to add an index to your temporary table.

MAX Subquery in SQL Anywhere Returning Error

In sqlanywhere 12 I wrote the following query which returns two rows of data:
SELECT "eDatabase"."Vendor"."VEN_CompanyName", "eDatabase"."OrderingInfo"."ORD_Timestamp"
FROM "eDatabase"."OrderingInfo"
JOIN "eDatabase"."Vendor"
ON "eDatabase"."OrderingInfo"."ORD_VEN_FK" = "eDatabase"."Vendor"."VEN_PK"
WHERE ORD_INV_FK='7853' AND ORD_DefaultSupplier = 1
Which returns:
'**United Natural Foods IN','2018-02-07 15:05:15.513'
'Flora ','2018-02-07 14:40:07.491'
I would like to only return the row with the maximum timestamp in the column "ORD_Timestamp". After simply trying to select by MAX("eDatabase"."OrderingInfo"."ORD_Timestamp") I found a number of posts describing how that method doesn't work and to use a subquery to obtain the results.
I'm having difficulty creating the subquery in a way that works and with the following query I'm getting a syntax error on my last "ON":
SELECT "eDatabase"."Vendor"."VEN_CompanyName", "eDatabase"."OrderingInfo"."ORD_Timestamp"
FROM ( "eDatabase"."OrderingInfo"
JOIN
"eDatabase"."OrderingInfo"
ON "eDatabase"."Vendor"."VEN_PK" = "eDatabase"."OrderingInfo"."ORD_VEN_FK" )
INNER JOIN
(SELECT "eDatabase"."Vendor"."VEN_CompanyName", MAX("eDatabase"."OrderingInfo"."ORD_Timestamp")
FROM "eDatabase"."OrderingInfo")
ON "eDatabase"."Vendor"."VEN_PK" = "eDatabase"."OrderingInfo"."ORD_VEN_FK"
WHERE ORD_INV_FK='7853' AND ORD_DefaultSupplier = 1
Does anyone know how I can adjust this to make the query correctly select only the max ORD_Timestamp row?
try this:
SELECT TOP 1 "eDatabase"."Vendor"."VEN_CompanyName", "eDatabase"."OrderingInfo"."ORD_Timestamp"
FROM "eDatabase"."OrderingInfo"
JOIN "eDatabase"."Vendor"
ON "eDatabase"."OrderingInfo"."ORD_VEN_FK" = "eDatabase"."Vendor"."VEN_PK"
WHERE ORD_INV_FK='7853' AND ORD_DefaultSupplier = 1
order by "ORD_Timestamp" desc
this orders them biggest on to and say only hsow the top row