Multiply every entry in column by a fixed number in SQL - sql

In SQL, say I have a table of the following layout:
id name age
1 george 12
2 tom 14
3 charles 19
4 henry 21
5 fiona 12
6 kate 14
...
If I discover that I've made a terrible inputting mistake, and that everybody is actually twice their age, is there a way to multiply the age column by 2 in one sweep instead of needing to painstakingly go through the whole column and edit each age individually (pretend I have 500 entries so manual work is out of the question).
Is there a SQL solution?

It's really easy:
UPDATE table SET age=age*2

Yes, run an update:
update theTable set age = age * 2
Depending on the settings in the database, you might not be allowed to run an update without a where (to protect against mistakes), then you would add a dummy comparison:
update theTable set age = age * 2 where 1 = 1

Related

SQL: Substitute values between columns

I have a (very simplified) (Oracle) table like this. The row number are only for better understanding, they have no deeper meaning.
Row
value
1
Jim
2
John
3
Mike
Now I find the "error" - the names are messed up. All "Jims" should be renamed to "John", John changes to Mike and Mike changes to Jim.
My first update changes Jim to John.
My second update should change John to Mike.
But the real problem is: Now I have two Johns - the old and the renamed Jim. How to find and modify the "old John" without changing the other?
My idea is to use temp-values:
Jim to temp_John
John to temp_mike
Mike to Jim
temp_John to John
temp_mike to Mike
Good idea? Or are there better ones? Or is it the totally wrong way?
Edit:
I reality, there are not three names, but 700 - 1000 numbers, so
25 to 345
558 to 2
1 to 38
...
Nah, it's just a single UPDATE with a CASE expression:
SQL> select * From test order by crow;
CROW VALU
---------- ----
1 Jim
2 John
3 Mike
SQL> update test set
2 value = case when value = 'Jim' then 'John'
3 when value = 'John' then 'Mike'
4 when value = 'Mike' then 'Jim'
5 end;
3 rows updated.
SQL> select * From test order by crow;
CROW VALU
---------- ----
1 John
2 Mike
3 Jim
SQL>
You can use decode:
update test set value = decode(value,'JIM','JOHN','JOHN','MIKE','MIKE','JIM');
db<>fiddle here
For numbers you can use negative numbers as a temporarity:
update test value = decode(value, 65537, -7777776777777, value);
update test value = decode(value, 7777776777777, -45, value);
update test value = decode(value, 45, -65537, value);
update test set value = abs(value);
This way you can have as many numbers as you want as it uses one query per number.
updated db<>fiddle here for numbers example
You should create a table with two columns:
create table value_pairs
(old_value integer,
new_value integer,
primary key (old_value));
After creating the table you have to insert the old and new values:
insert into value_pairs values (1, 2);
insert into value_pairs values (2, 3);
etc.
Finally run this SQL statement:
update your_table t
set value =
(select new_value
from value_pairs p
where p.old_value = t.value);
In this case you don't have to write long case or decode statements.

T-SQL 2008 INSERT dummy row WHEN condition is met

**Schema & Dataset**
id version payment name
1 1 10 Rich
2 1 0 David
3 1 10 Marc
4 1 10 Jess
5 1 0 Steff
1 2 10 Rich
2 2 0 David
3 2 10 Marc
4 2 10 Jess
5 2 0 Steff
2 3 0 David
3 3 10 Marc
4 3 10 Jess
http://sqlfiddle.com/#!3/1c457/18 - Contains my schema and the dataset I'm working with.
Background
The data above is the final set after a stored proc has done it's processing so everything above is in one table and unfortunately I can't change it.
I need to identify in the dataset where a person has been deleted with a payment total greater than 0 in previous versions and insert a dummy row with a payment of 0. So in the above example, Rich has been deleted in version 3 with a payment total of 10 on previous versions. I need to first identify where this has happened in all instances and insert a dummy row with a 0 payment for that version. Steff has also been deleted on version 3 but she hasn't had a payment over 0 on previous versions so a dummy row is not needed for her.
Tried so far -
So I looked at pinal dave's example here and I can look back to the previous row which is great so it's a step in the right direction. I'm not sure however of how to go about achieving the above requirement. I've been toying with the idea of a case statement but I'm not certain that would be the best way to go about it. I'm really struggling with this one and would appreciate some advice on how to tackle it.
You can do this by generating all possible combinations of names and versions. Then filter out the ones you don't want according to the pay conditions:
select n.name, v.version, coalesce(de.payment, 0) as payment
from (select name, max(payment) as maxpay from dataextract group by name) n cross join
(select distinct version from dataextract) v left outer join
dataextract de
on de.name = n.name and de.version = v.version
where de.name is not null or n.maxpay > 0;
Here is a SQL Fiddle.

SQL Creating new variables

I am fairly inexperienced with SQL, but am working to try to condense my code into one query so that it is more efficient. Below is a simplified example of a much more complex problem I have. I am having problems with the syntax of creating the summary groups and variables. In my case, the data are housed in several different table, but the joins are not a problem for me so I have only created one table here.
This is the data I have:
Name Class Wk Score ExCred X
Joe A 1 35 ? 3
Hal A 1 50 5 4
Sal A 1 45 ? 3
Kim B 1 30 5 6
Cal B 1 40 ? 6
Joe A 2 50 ? 2
Hal A 2 40 ? 3
Sal A 2 40 ? 4
Kim B 2 40 5 5
Cal B 2 40 ? 4
The table I am trying to create will look like this:
Class Wk Avg_Score Sum_X
A 1 45 10
B 1 37.5 12
A 2 43.3 9
B 2 42.5 9
So, the data are summarized by class and week. The avg_score is the average of the sum and 'score' and 'ExCred' for each student. Sum_X is simply the sum of X for each class.
I have had success with this in SAS SQL by using multiple proc means statements, but this is clunky and seems to take a really long time. There has to be a more elegant way to do this. I know it probably involves the group by statement..... Help?
Thanks. Pyll
I see no particular reason not to use proc means here. It should be significantly faster than proc sql on datasets of substantial size.
proc means data=have;
class class wk;
types class*wk;
var score x;
output out=want mean(score)= sum(x)=;
run;
Just preprocess the data to include ExCred into the Score variable; if execution time is an issue use a view to do so.
If you did want to do it in sql, you would indeed use a group by.
proc sql;
create table want as
select class, wk, mean(score+ex_cred), sum(x)
from have
group by class, wk;
quit;

How to execute a LIKE query against a DECIMAL (or INTEGER) field?

Is it possible to execute a LIKE statement against a table column that contains DECIMAL types? Or else, what would be the best way to select matching rows given a number in a decimal (or integer) field?
E.g.:
Name Age
... ...
John 25
Mary 76
Jim 45
Erica 34
Anna 56
Bob 55
Executing something like SELECT * FROM table WHERE age LIKE 5 would return:
Name Age
John 25
Jim 45
Anna 56
Bob 55
It is not clear from your question what exactly you are trying to achieve, but based on the example query, the filtering you need to do should be achievable using normal arithmetic operators.
SELECT * FROM table WHERE MOD(age, 10) = 5 -- All records where the age ends in 5
Or:
SELECT * FROM table WHERE MOD(age, 5) = 0 -- All records where age is divisible by 5
Now that you clarified that though you are using a DECIMAL field you are not actually using it as a numeric value (as if you would, the requirement wouldn't exist), the answers given by others are reasonable - convert the field to a text value and use LIKE on it.
Alternatively, change the type of the field to something that is more suitable to the way you are using it.
You can convert your decimal field to varchar and then apply like.
If you create a query
select name from table where age like '%5%'
you could achieve this (at least in mysql and db2)
But if you prefer to match a number you should use something like:
select name from table where age > minimum and age < maximum
Or try to compare against a modulo if you are really interested in querying on the last number.

SQL Update each record with its position in an ordered select

I'm using Access via OleDb. I have a table with columns ID, GroupID, Time and Place. An application inserts new records into the table, unfortunately the Place isn't calculated correctly.
I want to update each record in a group with its correct place according to its time ascending.
So assume the following data:
ID GroupId Time Place
Chuck 1 10:01 2
Alice 1 09:01 3
Bob 1 09:31 1
should result in:
ID GroupId Time Place
Chuck 1 10:01 3
Alice 1 09:01 1
Bob 1 09:31 2
I could come up with a solution using a cursor but that's AFAIK not possible in Access.
I just did a search on performing "ranking in Access" and I got this support.microsoft result.
It seems you create a query with a field that has the following expression:
Place: (Select Count(*) from table1 Where [Time] < [table1alias].[Time]) + 1
I can't test this, so I hope it works.
Using this you may be able to do (where queryAbove is the above query):
UPDATE table1
SET [Place] = queryAbove.[Place]
FROM queryAbove
WHERE table1.ID = queryAbove.ID
It's a long shot but please give it a go.
I don't think time is a number or time formatted column, time is unfortunately a text string containing the numbers and dilimetrs of the time format. This is why sorting after the time column is illegal. Removing the dilimiters ":" and "," casting to integer and then sorting numirically could do the job