Updating earliest record in SQL? - sql

I have a problem at the moment where I would like to update the earliest entry for a job in my table called Service_Log_Temp with duplicate = 'No' and the rest with duplicate = 'Yes'
Here is my table at the moment:
So I would like a script which looks at the K_B_Job_No (you'll see I have 2 different jobs listed here) and updates the earliest entry based on L1_GA_SR_Creation_Date & L2_B_Start_time_Of_Activity with Duplicate = 'No' and the rest with Duplicate = 'Yes'.
This is how it should look:
Any ideas?

try this
select key_service,k_r_job_no,L1_GA_SR_Creation_Date,L2_B_Start_time_Of_Activity,
case
when (select min(L1_GA_SR_Creation_Date) and min(L2_B_Start_time_Of_Activity)
then 'No'
else 'Yes'
end as Duplicate
from Service_Log_Temp
group by k_r_job_no

;with a as (select K_B_Job_No, min(L1_GA_SR_Creation_Date + cast(L2_B_Start_time_Of_Activity as datetime)) as dttime from Service_Log_Temp
group by K_B_Job_No)
select key_service,K_B_Job_No,L1_GA_SR_Creation_Date,L2_B_Start_time_Of_Activity,
(case when
(select dttime from a where a.K_B_Job_No=b.K_B_Job_No)=(L1_GA_SR_Creation_Date + cast(L2_B_Start_time_Of_Activity as datetime))
then 'NO' else 'YES' end) as Duplicate
from Service_Log_Temp b

this should work in postgres, where the concatenation is || - you must change that to whatever is the concatenation in your system
background: To find the time for the first run of each job :
select k_r_job_no,min( L1_GA_SR_Creation_Date+L2_B_Start_time_Of_Activity) from
service_log_temp
group by k_r_job_no
The problem is just that we cannot get the ids out from this query...
but we can use this as a subquery. As it is normally not possible to get more than one row out of a subquery, we have to do a concatenation to get the right time for each job: (you may need to do a type cast to get the concatenation to work)
select key_service from service_log_temp where
k_r_job_no||L1_GA_SR_Creation_Date+L2_B_Start_time_Of_Activity in(
select k_r_job_no||min( L1_GA_SR_Creation_Date+L2_B_Start_time_Of_Activity)
from service_log_temp
group by k_r_job_no
)
This can be rewritten as an update:
update service_log_temp set Duplicate='Yes' where
k_r_job_no||L1_GA_SR_Creation_Date+L2_B_Start_time_Of_Activity in(
select k_r_job_no||min( L1_GA_SR_Creation_Date+L2_B_Start_time_Of_Activity)
from service_log_temp
group by k_r_job_no
)
And then afterwards
update service_log_temp set Duplicate='No' where Duplicate is null
(or, use "case" as SRIRAM proposed if you want to have it in one query)

Related

SQL select statement to change two other column values based on a column that contains null

I would like to use a SQL select statement that has the condition 'where column A is NULL change column B values to be equal to column C values'. How would I be able to incorporate this logic into a SELECT statement (Not an UPDATE statement as I cant change the tables on the server but want to query them from the server).
SELECT final.*
FROM final
The actual table is in the image below, here I want to change column Old to match column DirectUse if the Change column is null.
Try Case statement:
SELECT
Name, NameSimple, DirectUse, Year, Month,
CASE WHEN Change IS NULL THEN DirectUse ELSE Old END AS Old,
CurrentCons, Change
FROM final;
CASE: https://www.w3schools.com/sql/sql_case.asp
Can also be incorporated by UNION ALL:
SELECT Old
FROM final where Change is not null
UNION ALL
SELECT DirectUse
FROM final where Change is null
Use a CASE expression:
SELECT Name, NameSimple, DirectUse, Year, Month,
CASE WHEN Change IS NULL THEN DirectUse ELSE Old END AS Old,
CurrentCons, Change
FROM final;
I think you basically you want:
SELECT
ColumnA
, CASE WHEN ColumnA IS NULL THEN ColumnC ELSE ColumnB END AS ColumnB
, ColumnC
, <any other columns>
FROM Final

Associated records

I'm pretty new to SQL. I'm trying to write a query that will grab records associated that share an value with the sought after record in a single query.
For example below, if one record has a 'No' in it, I want it to to then return all records that share a common 'Letter'
Letter;Present
A;Yes
A;No
A;Yes
B;Yes
B;Yes
B;Yes
Returning:
Letter;Present
A;Yes
A;No
A;Yes
Use a sub-query to find those No letters. Then search for rows where values first character is in the found No letters.
select * from table
where letter in (select letter from table where present = 'No');
You will need to use a subquery for that..
SELECT a.letter, a.present
FROM yourTable a
WHERE a.letter IN (SELECT letter
FROM yourTable
WHERE present = 'No');
What you do here is select all letters where present = 'NO' then you simply re-select from that group where your letter is in the list of letter that contains a No.
In other words, the subquery is a filter.
You can use the EXISTS clause:
SELECT *
FROM yourTable t1
WHERE EXISTS (SELECT 1
FROM yourTable t2
WHERE t1.Letter = t2.Letter
AND t2.Present = 'No')
The subquery will get every record with Present = No.
The main query will get every record that share the Letter value with a result from the subquery.

How can I update the value of multiple rows to a different specified value in the same column?

Say I have a table where there are product IDs, product desc., and the language of each desc. I would like it so that if there was a description with a NULL value for American-English, it would update to the British-English version of that the description for that product. Is there a way to do this using the update command in SQL?
I normally prefer this syntax for updating values in one table from values in another (or in this case the same) table, b/c it is easy to change the UPDATE...SET to a SELECT for testing and to quickly see what values would be updated.
UPDATE p_US
SET p_US.product_desc = p_GB.product_desc
FROM dbo.product p_US
INNER JOIN dbo.product p_GB ON p_US.productID = p_GB.productID
WHERE p_US.language_code = 'US'
AND p_GB.language_code = 'GB'
AND p_US.product_desc IS NULL
;
and then you can swap out the first two lines above with this for quick testing to see what would be updated:
SELECT p_US.productID, p_US.product,
oldDesc = p_US.product_desc, newDesc = p_GB.product_desc
update [table] set [column]= case [change factor] when '1' then 'X' else 'Y' end where [where clause]
Maybe:
UPDATE my_table SET desc=(SELECT desc from my_table WHERE my_table.id=id AND my_table.lang='british') WHERE lang='american' and desc is NULL;

Writing a single UPDATE statement that prevents duplicates

I've been trying for a few hours (probably more than I needed to) to figure out the best way to write an update sql query that will dissallow duplicates on the column I am updating.
Meaning, if TableA.ColA already has a name 'TEST1', then when I'm changing another record, then I simply can't pick a value for ColA to be 'TEST1'.
It's pretty easy to simply just separate the query into a select, and use a server layer code that would allow conditional logic:
SELECT ID, NAME FROM TABLEA WHERE NAME = 'TEST1'
IF TableA.recordcount > 0 then
UPDATE SET NAME = 'TEST1' WHERE ID = 1234
END IF
But I'm more interested to see if these two queries can be combined into a single query.
I am using Oracle to figure things out, but I'd love to see a SQL Server query as well. I figured a MERGE statement can work, but for obvious reasons you can't have the clause:
..etc.. WHEN NOT MATCHED UPDATE SET ..etc.. WHERE ID = 1234
AND you can't update a column if it's mentioned in the join (oracle limitation but not limited to SQL Server)
ALSO, I know you can put a constraint on a column that prevents duplicate values, but I'd be interested to see if there is such a query that can do this without using constraint.
Here is an example start-up attempt on my end just to see what I can come up with (explanations on it failed is not necessary):
ERROR: ORA-01732: data manipulation operation not legal on this view
UPDATE (
SELECT d.NAME, ch.NAME FROM (
SELECT 'test1' AS NAME, '2722' AS ID
FROM DUAL
) d
LEFT JOIN TABLEA a
ON UPPER(a.name) = UPPER(d.name)
)
SET a.name = 'test2'
WHERE a.name is null and a.id = d.id
I have tried merge, but just gave up thinking it's not possible. I've also considered not exists (but I'd have to be careful since I might accidentally update every other record that doesn't match a criteria)
It should be straightforward:
update personnel
set personnel_number = 'xyz'
where person_id = 1001
and not exists (select * from personnel where personnel_number = 'xyz');
If I understand correctly, you want to conditionally update a field, assuming the value is not found. The following query does this. It should work in both SQL Server and Oracle:
update table1
set name = 'Test1'
where (select count(*) from table1 where name = 'Test1') > 0 and
id = 1234

Use of CASE statement values in THEN expression

I am attempting to use a case statement but keep getting errors. Here's the statement:
select TABLE1.acct,
CASE
WHEN TABLE1.acct_id in (select acct_id
from TABLE2
group by acct_id
having count(*) = 1 ) THEN
(select name
from TABLE3
where TABLE1.acct_id = TABLE3.acct_id)
ELSE 'All Others'
END as Name
from TABLE1
When I replace the TABLE1.acct_id in the THEN expression with a literal value, the query works. When I try to use TABLE1.acct_id from the WHEN part of the query, I get a error saying the result is more than one row. It seems like the THEN expression is ignoring the single value that the WHEN statement was using. No idea, maybe this isn't even a valid use of the CASE statement.
I am trying to see names for accounts that have one entry in TABLE2.
Any ideas would be appreciated, I'm kind of new at SQL.
First, you are missing a comma after TABLE1.acct. Second, you have aliased TABLE1 as acct, so you should use that.
Select acct.acct
, Case
When acct.acct_id in ( Select acct_id
From TABLE2
Group By acct_id
Having Count(*) = 1 )
Then ( Select name
From TABLE3
Where acct.acct_id = TABLE3.acct_id
Fetch First 1 Rows Only)
Else 'All Others'
End as Name
From TABLE1 As acct
As others have said, you should adjust your THEN clause to ensure that only one value is returned. You can do that by add Fetch First 1 Rows Only to your subquery.
Then ( Select name
From TABLE3
Where acct.acct_id = TABLE3.acct_id
Fetch First 1 Rows Only)
Fetch is not accepting in CASE statement - "Keyword FETCH not expected. Valid tokens: ) UNION EXCEPT. "
select name from TABLE3 where TABLE1.acct_id = TABLE3.acct_id
will give you all the names in Table3, which have a accompanying row in Table 1. The row selected from Table2 in the previous line doesn't enter into it.
Must be getting more than one value.
You can replace the body with...
(select count(name) from TABLE3 where TABLE1.acct_id = TABLE3.acct_id)
... to narrow down which rows are returning multiples.
It may be the case that you just need a DISTINCT or a TOP 1 to reduce your result set.
Good luck!
I think that what is happening here is that your case must return a single value because it will be the value for the "name" column. The subquery (select acct_id from TABLE2 group by acct_id having count(*) = 1 ) is OK because it will only ever return one value. (select name from TABLE3 where TABLE1.acct_id= TABLE3.acct_id) could return multiple values depending on your data. The problem is you trying to shove multiple values into a single field for a single row.
The next thing to do would be to find out what data causes multiple rows to be returned by (select name from TABLE3 where TABLE1.acct_id= TABLE3.acct_id), and see if you can further limit this query to only return one row. If need be, you could even try something like ...AND ROWNUM = 1 (for Oracle - other DBs have similar ways of limiting rows returned).