Update columns in sequence - sql

I am busy writing a piece of SQL where I only want to update column 2 if the result from column 1 fits certain criteria.
In the example below I am looking for some kind of syntax which will allow me to execute one update before proceeding to the next so I can use the result from the first in the second.
CREATE TABLE #Rows
(
RowID INT IDENTITY
,Num1 INT
,Num2 INT
)
INSERT INTO #Rows
(
Num1,Num2)
VALUES
(1,10),
(1,10)
SELECT
*
FROM
#Rows
UPDATE
#Rows
SET
Num1 = CASE WHEN Num1 + Num2 < 20 THEN 10 --Update 1 : I want this statement to execute first
END
,Num2 = CASE WHEN Num1 + Num2 = 20 THEN 100 ELSE 700 --Update 2 : I want this statement to execute after Update 1
END
SELECT
*
FROM
#Rows
DROP TABLE #Rows
The result I get is as follows:
RowID Num1 Num2
1 10 700
2 10 700
I am hoping to get the following result:
RowID Num1 Num2
1 10 700
2 10 100
Any ideas?

Since Num1 is set to the result of an expression you can just re-use that expression in the second CASE statement:
UPDATE
#Rows
SET
Num1 = CASE
WHEN Num1 + Num2 < 20 THEN 10
END,
Num2 = CASE
WHEN CASE
WHEN Num1 + Num2 < 20 THEN 10
ELSE Num1
END + Num2 = 20 THEN 100
ELSE 700 --Update 2 : I want this statement to execute after Update 1
END
Yeah it's messy but it should work.
I suppose the alternative is to wrap the whole thing in a transaction and do two updates

I think you cant do that, you will have to two update statements or change the CASE conditions. SQL syntax is not designed for that, as far as I know.
Read more info here:
http://dev.mysql.com/doc/refman/5.0/es/update.html
http://www.postgresql.org/docs/9.1/static/sql-update.html

Related

SQL input value either single or multiple values

In SQL query if the input value is 0 then take input as all values of the column else consider input value only;
Let's say if the input city_num = 0 then run the query for all city numbers i.e 1 to 50 else run the query for the input city_num say 5.. How to code this?
if the City_num = 0 then Select * from emp where City_num in 1to 50
if the City_num = 5 then Select * from emp where City_num = 5
;
Add this WHERE statement:
WHERE city_num = ? OR 0 = ?
If you pass 0 then it is equivalent to:
WHERE city_num = 0 OR 0 = 0
and since 0 = 0 is always TRUE then it will fetch all the rows.
If you pass 5 then it is equivalent to:
WHERE city_num = 5 OR 0 = 5
and since 0 = 5 is always FALSE then it will fetch only the row for city_num = 5.
Try This:
DECLARE #input INT = 2;
SELECT * FROM TABLE1
WHERE (city_num= #input AND #input > 0) OR #input = 0;
I have assumed city_num is integer. Minor fix if varchar

Update Zero to One and One to Zero in SQL Server

I have a table with flag 0 and 1.
Please tell me how to update Zero to One and One to Zero
DECLARE #a INT, #b INT
SELECT #a = number
FROM zerone
WHERE number = 0
SELECT #b = number
FROM zerone
WHERE number = 1
BEGIN
IF #a = 0
UPDATE zerone
SET number = 1
WHERE #a = 0
ELSE IF #b = 1
UPDATE zerone
SET number = 0
WHERE #b = 1
END
This query is not working for me.
use the below query to update 0 to 1 and 1 to 0
update zerone set number= 1-number
Just this:
UPDATE zerone
SET number = CASE WHEN number = 1 THEN 0 ELSE 1 END;
you should also always consider NULL values in update operations and must explicitly filter them out
UPDATE zerone
SET number= case
when 1 then 0
when 0 then 1
end
WHERE number in (0,1)
Also your query will not work because you are assigning a single variable with a rows of data in the select statement.
SELECT #a = number
FROM zerone
WHERE number = 0
This does not work like as you are expecting and will only assign #a with value either NULL(if there are no rows) or with 0 if there is a row. If there are multiple rows even then it will have a single value 0
As you have seen there are so many ways to perform that task but in this case, I would prefer #Abdul Rasheed.
We can also use below IIF logical function in SQLSERVER2012 or above.
UPDATE zerone
SET number = IIF (number = 1, 0, 1)

SQL remove from running total

I have a problem that I don't know how to fix .. here is the code and wanting result
if object_id('tempdb..#A') IS NOT NULL drop table #A
create table #A (ID int, Value decimal(6,2), value2 decimal(6,2), Result decimal(6,2))
insert into #A (ID, Value, value2, Result)
values
(1, 10, 25, null),
(1, 10, 25, null),
(1, 10, 25, null),
(2, 10, 5, null),
(2, 10, 5, null),
select * from #A
So, I would like to take Value away from "value2", if there are left overs, just update it to 0, for next row i would take those "left overs" and use them to take away from, with next Value
I would like to get results like this...
ID Value value2 Result
1 10 25 0
----------------------------
1 10 25 0
----------------------------
1 10 25 5
----------------------------
2 10 5 5
----------------------------
2 10 5 10
So as you can see with ID 1 ... it would be:
10 - 25 = 0
10 - 15 = 0
10 - 5 = 5
I hope you understand what I am trying to do here ... let me know if I can explain more ...
You seem to want the cumulative sum of the difference, with no negative values allowed. Most databases support window functions, which include cumulative sums:
I am going to assume that id really specifies the ordering. You need some column that serves this purpose because SQL tables represent unordered sets and have no ordering.
But, something like this should work:
select a.*,
sum(case when value2 >= value then 0 else value - value2 end) over
(order by id) as result -- or whatever the column is that specifies the ordering
from #A a;
With help of Gordon and using some part of his idea ... i did something, that at this moment seems to work, but will need a lot of more testing
if object_id('tempdb..#testDataWithRunningTotal') IS NOT NULL drop table #testDataWithRunningTotal
select id, value, value2, cast(null as float) as Result
into #testDataWithRunningTotal
from #A order by id;
declare #runningTotal float = 0, #previousParentId int = null;
update #testDataWithRunningTotal
set
#runningTotal = Result = case when #previousParentId <> id
then value2 - value
else
case when ISNULL(#runningTotal,0) < 0 then value * (-1)
when value2 - value < 0 and ISNULL(#runningTotal,0) = 0 then value2
when value2 - value > 0 and ISNULL(#runningTotal,0) = 0 then value2 - value
else
case when #runningTotal - value < 0 and ISNULL(#runningTotal,0) = 0 then value
else #runningTotal - value
end
end
end,
#previousParentId = id
from #testDataWithRunningTotal
update tst
set Result = case when Result > 0
then 0
else Result * -1
end
from #testDataWithRunningTotal tst
select * from #testDataWithRunningTotal
So, I am keeping #runningTotal running with update, and allowing it to go under 0 ... once it goes less then 0 it means that is moment where SUM of value is greater then SUM of Value2 ... so i keep the record there, and at end of this calculation i do update.

How to find Running Multiplication

Not sure is this the right title. I need to find the cumulative multiplication as like running total.
Searched the forum and got a excellent answer. But it is not the exact answer for me.
so modified the answer to my requirement.
SELECT *,
(SELECT CASE
WHEN Min(Abs(Column1)) = 0 THEN 0
ELSE Exp(Sum(Log(Abs(NULLIF(Column1, 0))))) -- the base mathematics
* Round(0.5 - Count(NULLIF(Sign(Sign(Column1) + 0.5), 1))%2, 0) -- pairs up negatives
END
FROM TEMP a
WHERE B.ID >= A.ID) as Running_Mul
FROM TEMP B
And I got my answer. Now Is there any better way of doing this in Sql Server 2008?
Sample data:
ID Column1
-- -------
1 1
2 2
3 4
4 8
5 -2
Expected Result:
ID Column1 Running_Mul
-- ------- -----------
1 1 1
2 2 2
3 4 8
4 8 64
5 -2 -128
Sql Fiddle
Your method is pretty reasonable. Good catch on the nullif() in the sum(), by the way. Although the else clause is computed only after the then, components of the else are calculated during the aggregation -- so log(0) would return an error.
I think there are some simpler ways to calculate the sign, such as:
power(-1, sum(case when column1 < 0 then 1 else 0 end))
or:
(case when sum(case when column1 < 0 then 1 else 0 end) % 2 = 0 then 1 else -1 end)
However, which version is "simpler" is a matter of opinion.
Here is another approach which I use in my SPs :
USE DB
GO
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
GO
IF(OBJECT_ID('TEMP') IS NOT NULL)
DROP TABLE TEMP
CREATE TABLE TEMP (ID INT, Column1 INT)
INSERT INTO TEMP VALUES
(1,1),
(2,2),
(3,4),
(4,8),
(5,-2)
DECLARE #result TABLE(ID INT, Column1 INT, calc INT)
DECLARE #Calc INT = 1
INSERT INTO #result (ID,Column1)
SELECT ID,Column1 FROM TEMP ORDER BY ID
UPDATE #result SET #Calc = calc = Column1 * #Calc
SELECT * FROM #result
I found a blog in which different methods to solve such problem, have been compared. check here.

Use comparison signs inside a sql case statement

I'm looking for a way to build case statements in a sql select query using less than and greater than signs. For example, I want to select a ranking based on a variable:
DECLARE #a INT
SET #a = 0
SELECT CASE
WHEN #a < 3 THEN 0
WHEN #a = 3 THEN 1
WHEN #a > 3 THEN 2
END
I'd like to write it as:
DECLARE #a INT
SET #a = 0
SELECT CASE #a
WHEN < 3 THEN 0
WHEN 3 THEN 1
WHEN > 3 THEN 2
END
...but SQL doesn't let me use the < and > signs in this way. Is there a way that I can do this is SQL 2005, or do I need to use the code like in the first one.
The reason for only wanting the code there once is because it would make the code a lot more readable/maintainable and also because I'm not sure if SQL server will have to run the calculation for each CASE statement.
I'm looking for a VB.NET case statement equivelent:
Select Case i
Case Is < 100
p = 1
Case Is >= 100
p = 2
End Select
Maybe it's not possible in SQL and that's ok, I just want to confirm that.
You can use the SIGN function as
DECLARE #a INT
SET #a = 0
SELECT CASE SIGN(#a - 3)
WHEN -1 THEN 0
WHEN 0 THEN 1
WHEN 1 THEN 2
END
If #a is smaller than 3, then #a - 3 results in a negative int, in which SIGN returns -1.
If #a is 3 or greater, then SIGN returns 0 or 1, respectively.
If the output you want is 0, 1 and 2, then you can simplify even more:
DECLARE #a INT
SET #a = 0
SELECT SIGN(#a - 3) + 1
Using SIGN as suggested by #Jose Rui Santos seems a nice workaround. An alternative could be to assign the expression an alias, use a subselect and test the expression (using its alias) in the outer select:
SELECT
…,
CASE
WHEN expr < 3 THEN …
WHEN expr > 3 THEN …
END AS …
FROM (
SELECT
…,
a complex expression AS expr
FROM …
…
)
SELECT
CASE
WHEN ColumnName >=1 and ColumnName <=1 THEN 'Fail'
WHEN ColumnName >=6 THEN 'Pass'
ELSE 'Test'
END
FROM TableName