insert values into a table's column and update that column - sql

I want to insert values into a table's column and for every value inserted I want to copy all the rows `wHERE anotherColumn ='someString'
Then I want to update the id of the rows inserted based on the name they have (rN).
Table definition:
myFirstTable
rN rID rnk dateR value1 value2 calculation1 calculation2 calculation3
abc_3m 3 abc_3mxfx 20.10.2010 1 3 4 3 0.33
abc_6m 4 abc_6mxfx 20.10.2010 2 1 3 8 4
First, let's insert new values in rN. Values taken where rN = abc_6m
insert into #myFirstTable (rN)
values
('abc_6m'), ('abc_1y'), ('abc_2y'), ('abc_3y'), ('abc_4y'), ('abc_5y'), ('abc_7y'), ('abc_10y'), ('abc_15y'), ('abc_30y')
query 1
update #myFirstTable
set rN = (select * from #myFirstTable
where rN = 'abc_6m')
where rN in (
'abc_6m', 'abc_1y', 'abc_2y', 'abc_3y', 'abc_4y', 'abc_5y', 'abc_7y', 'abc_10y', 'abc_15y', 'abc_30y'
)
The table would become:
#myFirstTable
rN rID rnk dateR value1 value2 calculation1 calculation2 calculation3
abc_3m 3 abc_3mxfx 20.10.2010 1 3 4 3 0.33
abc_6m 4 abc_6mxfx 20.10.2010 2 1 3 8 4
abc_1y 4 abc_6mxfx 20.10.2010 2 1 3 8 4
abc_2y 4 abc_6mxfx 20.10.2010 2 1 3 8 4
and so on, for all the values inserted.
then i want to update the rID to the correct value so the column rID would look like this:
rN rID rnk dateR value1 value2 calculation1 calculation2 calculation3
abc_3m 3 abc_3mxfx 20.10.2010 1 3 4 3 0.33
abc_6m 4 abc_6mxfx 20.10.2010 2 1 3 8 4
abc_1y 5 abc_6mxfx 20.10.2010 2 1 3 8 4
abc_2y 6 abc_6mxfx 20.10.2010 2 1 3 8 4
In order to do so, I was thinking of writing something like this:
query 2
update #myFirstTable
set rID = (case when rnk = 'abc_1y' then rID = '100',
case when rnk = 'abc_2y' then rID = '101'
case when rnk = 'abc_3y' then rID = '102'
case when rnk = 'abc_4y' then rID = '103'
case when rnk = 'abc_5y' then rID = '104'
case when rnk = 'abc_7y' then rID = '105'
case when rnk = 'abc_10y' then rID = '106'
case when rnk = 'abc_15y' then rID = '107'
case when rnk = 'abc_30y' then rID = '108'
) end
select * from #myFirstTable
where rN = 'abc_6M'
Questions:
1. Is my logic correct for what I'm trying to achieve? (are query1 and query2 ok syntax wise? Can I write something like this in sql server 2012?
2. Is it ok to write an update column = (case when column = then another column = 'value' like that ?
3. Could I do this in a simpler way somehow using a window function?
ex:
select * from myTable
case (
when rN not in ('abc_1m', 'abc_3m', 'abc_6m') then
select * from #myFirstTable where rN like 'abc_6m'
over (partition by (select * from #myFirstTable where rN like 'abc_6m'))) end
Sorry if I'm not phrasing the question in the most clear way, but I am not sure what I could use and how to use it, that's why I'm looking for some guidence.
Thanks

EDIT:
I'm only a beginner and this is the best I could come up with, which seems to be what you want to do. Following steps are building up on the already existing table with the two rows called MyFirstTable.
1. step (inserting additional values in the rN column):
INSERT INTO MyFirstTable (rN)
VALUES ('abc_1y'),('abc_2y'),('abc_3y'),('abc_4y'),('abc_5y'),('abc_7y'),('abc_10y'),('abc_15y'),('abc_30y');
2. step (dropping rID column and creating a new one with auto_incremeneted values)
ALTER TABLE MyFirstTable
DROP COLUMN rID;
ALTER TABLE MyFirstTable
ADD rID int IDENTITY(3,1);
More info: http://www.w3schools.com/sql/sql_autoincrement.asp
3. step (updating fields in other columns with values from the 2nd row)
Here, the update is combined with something called "self-join", because the FROM clause doesn't allow us to use the same source table as the one that is being updated and so nested query to retrieve the desired value cannot be used.
UPDATE t1
SET
t1.rnk = t2.rnk,
t1.dateR = t2.dateR,
t1.value1 = t2.value1,
t1.value2 = t2.value2,
t1.calculation1 = t2.calculation1,
t1.calculation2 = t2.calculation2,
t1.calculation3 = t2.calculation3
FROM MyFirstTable t1
LEFT JOIN MyFirstTable t2 ON t2.rN='abc_6m'
WHERE t1.rN in ('abc_1y','abc_2y','abc_3y','abc_4y','abc_5y','abc_7y','abc_10y','abc_15y','abc_30y');
More info on self-join: https://technet.microsoft.com/en-us/library/ms177490%28v=sql.105%29.aspx
I found this answer to be helpful: https://stackoverflow.com/a/5574558/4296411
Warning: I'm really only a beginner and possibly none of the above may be considered a good practice and might contain mistakes leading to unpredictable results. :) It nevertheless seems to be answering your problem. Good luck!
EDIT2:
Well, this is most probably a ridiculous overkill, but since you cannot drop the rID column, I was able to come up with this rather complex solution. First, you would perform step #1, then the step#3 and then:
DECLARE #i INT = 1;
WHILE #i <= (SELECT COUNT(rN) FROM MyFirstTable WHERE rN IN ('abc_1y','abc_2y','abc_3y','abc_4y','abc_5y','abc_7y','abc_10y','abc_15y','abc_30y')) -- getting number of desired loops based on rows to be affected
BEGIN
UPDATE MyFirstTable
SET rID = 4+#i -- using number 4 as a starting point for incrementation and #i variable to perform the actual incrementation
WHERE
rN = ( -- specifying which row should be affected in each loop
SELECT SUBQUERY.rN
FROM ( -- assigning temporary row number for each desired row
SELECT ROW_NUMBER() OVER (ORDER BY value1) as row_num, rN -- using value1 in order to keep the current order (this doesn't seem to be a good practice, but it works)
FROM MyFirstTable
WHERE rN IN ('abc_1y','abc_2y','abc_3y','abc_4y','abc_5y','abc_7y','abc_10y','abc_15y','abc_30y')
) as SUBQUERY
WHERE SUBQUERY.row_num = #i
)
SET #i = #i + 1;
END;
PS: Please don't worry about my slight obsession with your problem. :D It's just that I consider this problem fun and It helps me to educate myself further.

Related

I'm trying to take a record from, for example row 1 and insert it into row 3

I have a field called RecordType that has three different records, 1, 2, 3. Each hold different records. I want to take the the balance from another field I have called Limit from RecordType 1 and insert it into RecordType 3 but I'm just unsure on how to do this. This will be going into a Crystal Report and I want to be able to suppress the RecordType 1 altogether.
I've tried a simple case statement but that's about it, I can't really think of any other ways to do it (I'm sure there's loads).
CASE
WHEN FA.RecordType = 3 THEN
FA.Limit
END AS LimitTest
Current results
Record Type
Limit
1
5,000,301
2
0
3
0
Expected Results
Record Type
Limit
2
0
3
5,000,301
You seem to want to combine the limit for types 1 and 3. You can do this with aggregation on an expression:
select (case when recordtype = 1 then 3 else recordtype end) as recordtype,
sum(limit) as limit
from t
group by (case when recordtype = 1 then 3 else recordtype end);
You can try using sub-query and a Case statement in your select statement, for example:
SELECT [RecordType],
(CASE [RECORDTYPE] WHEN 3 THEN
(SELECT LIMIT from Table_1 WHERE RECORDTYPE = 1)
ELSE LIMIT END) LimitTest
FROM TABLE_1 WHERE RECORDTYPE <> 1
You said:
Sorry my formatting is terrible I'm not sure how to do it properly. But to answer your question no type 1 & 3 will never have the same value as 3 never has a value. I want to basically move the value from type 1 into type 3
Which makes me think that this would be the simplest:
DELETE FROM table WHERE RecordType = 3
UPDATE table SET RecordType = 3 WHERE RecordType = 1
3 never has a value so let's get rid of them first, then 1 has the value but we want it to be 3 so just update all the 1s to be 3s instead
If you're not into deleting it, just mask it instead:
SELECT 3 as RecordType, Limit FROM table WHERE RecordType = 1
If you want to move value from type 1 to type 3 then do simple update in your query.
update t set t.value= t1.value from table as t , table as t1 where t.recordtype=3 and t1.recordtype=1
or
delete from table where recordtype = 3
update recordtype set recordtype=1 where recordtype=3
This will work may be
SELECT
IIF(A.RECORDTYPE = 1,3,A.RECORDTYPE) AS RECORDTYPE,
A.LIMIT
FROM
(
SELECT 1 RECORDTYPE,5000301 LIMIT UNION ALL
SELECT 2 RECORDTYPE,0 LIMIT UNION ALL
SELECT 3 RECORDTYPE,0 LIMIT
) A
WHERE A.RECORDTYPE IN (1,2)
ORDER BY RECORDTYPE
Check this if works for you.

How to compare a number with count result then use it in limit statement in redshift/sql

I have a table with two columns id and flag.
The data is very imbalanced. Only a few flag has value 1 and others are 0.
id flag
1 0
2 0
3 0
4 0
5 1
6 1
7 0
Now I want to create a balanced table. Therefore, I want get a subset from flag = 0 based on the number of records where flag = 1. Also, I don't want the number to be greater than 1000.
I am thinking about a code like this:
select *
from table
where flag = 0
order by random()
limit (least(1000,
select count(*)
from table
where flag = 1));
Expected result(Only two records have flag as 1 so I get two records with flag as 0, if there are more than 1000 records have flag as 1 I will only get 1000.):
id flag
2 0
7 0
If you want a balanced sample:
select t.*
from (select t.*, row_number() over (partition by flag order by flag) as seqnum,
sum(case when flag = 1 then 1 else 0 end) over () as cnt_1
from t
) t
where seqnum <= cnt_1;
You can change this to:
where seqnum <= least(cnt_1, 1000)
If you want an overall maximum.
You can use row_number to simulate LIMIT.
select * from (
select column1, column2, row_number() OVER() AS rownum
from table
where flag = 0 )
where rownum < 1000
If I’ve made a bad assumption please comment and I’ll refocus my answer.

SQL check if the value is more than 4 then update the other column stop the updates

I I have one tables updating two columns if the second column the update more or equal to 4 set the other column to 0
Tried case statement .... but still not working please help!
update [dbo].[QueuedSms_TEST]
set issent = 0,pendingstatusid = pendingstatusid + 1
where sendresponse is null
while (select pendingstatusid from [dbo].[QueuedSms_TEST]) > 3
update [dbo].[QueuedSms_TEST]
set issent = -1
First you create a temporal query to get a row_number, and then update that with the required rules.
SQL Demo
WITH cte as (
SELECT *,
ROW_NUMBER() OVER (ORDER BY pendingstatusid) as rn
FROM QueuedSms_TEST
)
UPDATE cte
SET pendingstatusid = rn,
issent = CASE WHEN rn > 3
THEN -1
ELSE 0
END;

Subtract value to multiple rows

Well I am stuck at a point where I need to distribute a value across multiple rows. Since I do not know the specific term, I would put it in the form of example below for better understanding:
Assuming the value of x to be 20, I need to distribute/subtract it to rows in descending order.
TABLE:
ID Value1
1 6
2 5
3 4
4 3
5 9
Result should look like: (x=20)
ID Value1 Answer
1 6 14
2 5 9
3 4 5
4 3 2
5 9 0
Can anyone just give me an idea how I could go with this?
Untested for syntax, but the idea should work in SQL Server 2005 and newer.
SQL Server 2012 has SUM OVER clause which makes this even handier.
SELECT ID, Value1, CASE WHEN 20-SumA < 0 THEN 0 ELSE 20-SumA END AS Answer
FROM TABLE A
CROSS APPLY (SELECT SUM(B.Answer) SumA FROM TABLE B
WHERE B.ID <= A.ID) CA
It is perhaps easier to think of this problem in a different way. You want to calculate the cumulative sum of value1 and then subtract that value from #X. If the difference is negative, then put in 0.
If you are using SQL Server 2012, then you have cumulative sum built-in. You can do this as:
select id, value1,
(case when #X - cumvalue1 < 0 then 0 else #X - cumvalue1 end) as answer
from (select id, value1,
sum(value1) over (order by id) as cumvalue1
from table t
) t;
If you don't have cumulative sum, you can do this with a subquery instead:
select id, value1,
(case when #X - cumvalue1 < 0 then 0 else #X - cumvalue1 end) as answer
from (select id, value1,
(select sum(value1)
from table t2
where t2.id <= t.id
) as cumvalue1
from table t
) t;
I don't understand your question. I know what I think you're trying to do. But your example doesn't make sense.
You say you want to distribute 20 over the 5 rows, yet the sum of the difference between Value1 and Answer is only 3 (8+4+1+-1+-9).
And how do you want to distribute the values? Using a spread/split based on the value in Value1?
Edit: I made an example which splits 20 over the values you've specified above:
DECLARE #x FLOAT = 20.0
DECLARE #values TABLE (
ID INT,
VALUE FLOAT,
NEWVAL FLOAT)
INSERT INTO #values (ID, VALUE) VALUES (1,6), (2,5),(3,4),(4,3),(5,9)
UPDATE f
SET [NEWVAL] = [newValue]
FROM #values f
INNER JOIN (
SELECT
ID,
value + ((VALUE / [maxValue]) * #x) [newValue]
FROM
#values
CROSS APPLY (
SELECT
SUM(value) [maxValue]
FROM
#values
) m
) a ON a.ID = f.ID
SELECT * FROM #values
Unfortunately I had to change your values to floats for this to work. If you require them as integers, you'll need to use rounding and then calculate the difference of the sum of new value - #x and then spread the difference over the rows (if > 1 then add to lowest number, if < 1 subtract from largest value). Your rounding should be usually just 1 or 2.
I don't even know if I this is what you're trying to do yet.

Recursive SQL query - using results from query within query

I'm running SQL Server 2012, and here's what I need:
Row Field1 Field2
1 0 1
2 ? 2
3 ? -5
I need a query that will go throw row by row.
It should take row2,field1 and set it equal to row1,field1+row2,field2
It then would take row3,field1 and set it equal to row2,field1+row3,field2
Initially the table has values in Field1 that are all equal to 0, and so when I run my query it just always uses 0 for the field1 values.
Any help would be appreciated. I was thinking a CTE would be the way to go, but I just don't know where to go with that.
Edit:
Just to clear up some things, in my example. The initial input would be
Row Field1 Field2
1 0 1
2 0 2
3 0 -5
The desired output would be:
Row Field1 Field2
1 1 1
2 3 2
3 -2 -5
My actual table is a bit complicated, but I know I can apply it specifically if I could understand how to pull it off with this example.
Is this what you need? (Unclear if when you refer to row2,field1 for example you mean the before or after update value)
CREATE TABLE YourTable
(
Row INT,
Field1 INT NULL,
Field2 INT
)
INSERT INTO YourTable
VALUES (1,0,1),
(2,0,2),
(3,0,-5);
WITH CTE AS
(
SELECT *,
SUM(Field2) OVER (ORDER BY Row ROWS UNBOUNDED PRECEDING) AS RunningTotal
FROM YourTable
)
UPDATE CTE
SET Field1 = RunningTotal
SELECT *
FROM YourTable
Final Result
Row Field1 Field2
----------- ----------- -----------
1 1 1
2 3 2
3 -2 -5
Or another (more literal) interpretation of your word problem might be
WITH CTE AS
(
SELECT *,
LAG(Field2) OVER (ORDER BY Row) AS PrevRowField2
FROM YourTable
)
UPDATE CTE
SET Field1 = PrevRowField2 + Field1
WHERE PrevRowField2 IS NOT NULL
Something like this adapted from TSQL A recursive update?
With cte As (
Select
Row,
Field1,
Field2
From
t
Where
Row = 1
Union All
Select
t.Row,
t.Field2 + c.Field1,
t.Field2
From
t
Inner Join
cte c
On t.Row = c.Row + 1
)
Update
t
Set
Field1 = c.Field1
From
t
inner join
cte c
On t.Row = c.Row
http://sqlfiddle.com/#!6/cf843/1