MySQL: Set a 2 variables from 2 columns from a single table - mysql

In the LOAD DATA documentation, there's a SET syntax which allows values to be assigned to column.
...
SET col=#variable;
...
I was wondering if the SET can support assignment from 2 columns from a single table, I can't find anything in the documentation that supports tuple assignment:
...
SET (col1, col2) = (SELECT col1, col2 from table where id=1);
...
Anyone have any knowledge on this? Thank you!

Set doesn't work like this, however I know that in TSQL at least you can do the same thing using select.
Select #var1 = col1, #var2= col2
from table

Related

SQL how to use a formula to fill a column like in Excel

My database is in MySQL
I have a table, let's say of 4 columns.
I would like to know if it's possible, and how to implement the following: fill the 4th column according to the value of the column 2 and column 3
In Excel I have a formula, let's give an example: if column2 value is set to "grey" and column3 value is set to "car", then column 4 value should be set to "super"
I just say this as an example.
My real formula in Excel looks like this: =IF(K4=4;"Maximal";IF(K4>4;"Maximal";IF(K4=3;"Important";IF(K4>3;"Important";IF(K4=2;"Limited";IF(K4>2;"Limited";IF(K4=1;"Forgettable";IF(K4>1;"Forgettable";"error"))))))))
However I want to do it in SQL.
I was thinking of creating my table until the column 3, set column 4 to NULL or empty, then open a GUI written in Java and maybe there do a piece of code to automatically fill the column 4 according to what is in column 2 and column 3 (these values will be choosable via Choicelist).
But if there is a way to do it directly in SQL, I am interested
Thx a lot in advance for your help.
regards
Yes. you can easily update your NULL-values according to some requirements for the other values in other columns of a particular row with the Update statement
UPDATE <tablename>
SET <column> = 'value'
WHERE <condition>
The only drawback here might be that you have to create an update statement for each of the combinations of your values in column2 and column3. (however, it's not much work for your amount of conditions).
I created an example (demo):
Creating a table in SQL according to your example could look like this,I used a temporary one for the sake of an example:
CREATE GLOBAL TEMPORARY TABLE demoTable (
"Col1" VARCHAR2(50 BYTE) NOT NULL,
"Col2" VARCHAR2(50 BYTE) NOT NULL,
"Col3" VARCHAR2(50 BYTE) NOT NULL,
"Col4" VARCHAR2(50 BYTE) DEFAULT NULL
)
ON COMMIT PRESERVE ROWS
I also inserted some dummy data:
INSERT INTO demoTable VALUES ('Charles', 'grey', 'car', NULL);
INSERT INTO demoTable VALUES ('Alice', 'grey', 'bike', NULL);
INSERT INTO demoTable VALUES ('Bob', 'red', 'car', NULL);
The result:
Now, create the update statements like this, for example:
UPDATE demoTable dt
SET dt."Col4" = 'super'
WHERE dt."Col2" = 'grey' AND dt."Col3" = 'car';
The result
You can try like this;
select * from mytable
COL1 COL2
---- --------------------
0 -
1 -
2 -
3 -
4 -
4 record(s) selected.
update mytable Set Col2 =
Case
When Col1<1 Then 'error'
When Col1=1 Then 'Forget'
When Col1=2 Then 'Limited'
When Col1=3 Then 'Important'
When Col1=4 Then 'Maximal'
End"
select * from mytable"
COL1 COL2
---- --------------------
0 Error
1 Forget
2 Limited
3 Important
4 Maximal
4 record(s) selected.
You can create a sql function, lets say udfGetColumn4Value taking in the column2, column3 as parameters to it and return a value.
Now you can run a select column2, column3, udfGetColumn4Value(column2, column3) from table or a query as desired. Hope this helps.
You were not very precise regarding which DBMS you're using. And also about the exact logic behind using your two columns.
Still here comes a probable SQL-Server solution, where I have taken one statement using CASE WHEN with your example and concatenated your two columns col2 and col3 (you can apply your further logic of here) otherwise:
UPDATE TableName
SET Col4 = CASE WHEN col2 = 'red' AND col3 = 'car' THEN 'super' ELSE col2 + col3 END;
You should replace col2 + col3 with your further logic.
Seems that a simple UPDATE-Query could address your problem:
update things set result = "super" where thing = "car" and color = "grey";
The where-clause does what you desire to do by saying
fill the column 4 according to what is in column 2 and column 3
I created a test table here on turorialspoint, there you can check if it fits your needs.

Converting from SQL Server to MySQL - MERGE

I'm converting Stored Procedures from SQL Server to MySQL and I've found a query that has me stumped:
IF EXISTS (SELECT * FROM dbo.T_ExampleTable WHERE Col1 = #Col1 AND Col2 = #Col2 AND Col3 = #Col3)
SET #return_value = -10
ELSE IF EXISTS (SELECT * FROM dbo.T_ExampleTable WHERE Col1 = #Col1 OR Col2 = #Col2 OR Col3 = #Col3)
SET #return_value = -20;
IF #return_value = 0
BEGIN
MERGE ExampleDB.dbo.T_ExampleTable AS T
USING (VALUES (#Col1, #Col2, #Col3)) AS S (Col1, Col2, Col3)
ON T.Col1 = S.Col1
WHEN NOT MATCHED THEN
INSERT VALUES (S.Col1, S.Col2, S.Col3);
END
For security purposes, I have altered the names of variables but the syntax is the same.
I think I have a grasp on what's happening with the MERGE here (but please correct me if I'm wrong). I assume that we're taking our 3 variables (#Col1, #Col2, and #Col3) and placing them in a result set we call "S". Then, we're checking each row in T_ExampleTable for a matching Col1 value. Finally, we're saying if it DOESN'T match in any of the rows, INSERT these values.
Now, I'm not too familiar with the MERGE syntax, so I may be off with the above assumption. Assuming I'm correct, however, isn't this the same as just performing a SELECT FROM T_ExampleTable WHERE Col1 = #Col1, then checking the ##ROWCOUNT (or FOUND_ROWS() in MySQL) and if it doesn't equal 0, performing an INSERT?
Furthermore, I am even more baffled by logic above the MERGE. If my understanding of how MERGE works is correct (and again, it may be off) then the entire statement is pointless. Because basically, if #Col1 exists within the T_ExampleTable, then #return_value is going to equal -10 or -20. Thus, it can't equal 0 and we won't hit the MERGE. If #Col1 does not exist within T_ExampleTable, then #return_value is going to equal 0, but the MERGE isn't going to return any result set since T.Col1 = S.Col1 will never be true.
This is why I believe I must be misunderstanding something about how MERGE works. Either that, or the SQL Server code I'm porting is just poorly written (which is also possible, I guess).
So ultimately, I'm looking for two answers here. One that helps clarify what the logic of a MERGE statement is and if my understanding of the above code is correct, and another that shows the possible solution for converting this to MySQL.
Thanks!
For practical purposes, I think this is equivalent to this (in both databases):
INSERT INTO T(Col1, Col2, Col3)
SELECT col1, col2, col3
FROM (SELECT #Col1 as col1, #Col2 as col2, #Col3 as col3) s
WHERE NOT EXISTS (SELECT 1
FROM ExampleDB.dbo.T_ExampleTable t
WHERE t.col1 = s.col1
);
There may be some edge cases where they are not exactly the same -- say, in terms of concurrent calls to the stored procedure or when col1 is NULL. But you already have differences in locking between the two databases anyway.
(And, although you didn't ask, I would expect Postgres to be a more natural database to switch to from SQL Server because Postgres and SQL Server have a larger overlap in functionality.)

Duplicating records in the same MySQL table has duplicate entry for key

Is there a way to use a MySQL INSERT similar to the following:
INSERT INTO doc_details SELECT * FROM doc_details WHERE dd_id = 1
This doesn't work because the primary key is being repeated and it can get very long-winded expanding the columns out.
The purpose of this is to duplicate rows in the same table which will get modified later, retrieving the last_insert_id for the new record. So ideas for other ways to do this would be appreciated too.
Thanks.
Simply name the columns you want to duplicate and omit the primary key:
INSERT INTO doc_details (col1, col2, col3)
SELECT col1, col2, col3
FROM doc_details
WHERE dd_id = 1
I'd suggest you to make ID field with AUTO_INCREMENT option, then use NULL values when inserting -
INSERT INTO doc_details(id, column1, column2)
SELECT NULL, column1, column2 FROM doc_details WHERE dd_id = 1;
In this case old ID will be changed with new ones.
You can depend on temporary table to copy from old record and omitting the key field value.
You have to use at least one named column, i.e. the key field name, to omit its repeating values.
See the following example:
CREATE TEMPORARY TABLE tmp SELECT * from doc_details WHERE dd_id = ?;
ALTER TABLE tmp drop pk_field_name_here; -- drop the key field for not repeating
INSERT INTO doc_details SELECT 0, tmp.* FROM tmp;
DROP TABLE tmp;
You can observe that no other filed names are used but the key field name to omit it's value.
You can also refer to my answer to a similar posting at: Mysql: Copy row but with new id.
Thanks for the answers. Really appreciated. Because most answers specify the column, this led to some extra research that said 'wildcards cannot be used in INSERT statements. Select, Modify and insert into the same table
I managed to solve this in my application with a separate SELECT then the INSERT with the columns expanded with a Perl map function:
SELECT * FROM doc_details WHERE dd_id = 1
Then in Perl, with the row as a hash reference in $data:
$data->{'dd_id'} = 0;$columns = join(',', map {$_ .'='. $dbh->quote( $data->{$_} ) } keys %{$cdh} );
Does the trick nicely - it copies the row regardless of changes to the column structure/order as long as the auto_increment column is maintained.
I know it's not a pure SQL solution - although Ravinder provided one that was.
Thanks to all!

INSERT result of a SELECT and other values as well

I want to know if this is possible without a procedure or server side calls into the database.
I am trying to insert values into a table based on a select, and other values that will be provided from the server.
The select statement will return more than one result.
I am aware of the existence of INSERT SELECT, but is there any SELECT INSERT ? or a way to insert based on the results of a select ?
thank you
Not really sure what seems to be the problem.
You can do like this:
INSERT INTO table (columns)
SELECT
column or column expression1,
column or column expression2,
…
constant or constant expression1,
constant or constant expression2,
…
FROM a set of tables/joins
WHERE …
Not necessarily in that order (columns, then constants), no. You can mix columns with constants any way you like, just follow the order of the columns you are inserting into.
Was that what you were asking about?
I don't see why an
INSERT INTO yourtable(col1, col2, col3)
SELECT col1, col2, col3
FROM yourothertable
doesn't work for you. But you could always do a SELECT INTO #temptable to save your query in a temporary table and then you could INSERT that data or manipulate it prior to inserting. This is just a long way around the original idea, though.
Am I misunderstanding your questions?
Yes. Use this query:
INSERT INTO FOO (oof, rab) SELECT (foo, bar) FROM BAR;
I think you can do this:
INSERT INTO targetTable (col1, col2, col3)
SELECT col1, col2, col3 FROM sourceTable
UNION ALL
SELECT 'something' AS col1, 'something else' AS col2, 'yet something else' AS col3 FROM DUAL;

Is it really no solution to update multiple records in MySQL?

I want to do all these update in one statement.
update table set ts=ts_1 where id=1
update table set ts=ts_2 where id=2
...
update table set ts=ts_n where id=n
Is it?
Use this:
UPDATE `table` SET `ts`=CONCAT('ts_', `id`);
Yes you can but that would require a table (if only virtual/temporary), where you's store the id + ts value pairs, and then run an UPDATE with the FROM syntax.
Assuming tmpList is a table with an id and a ts_value column, filled with the pairs of id value, ts value you wish to apply.
UPDATE table, tmpList
SET table.ts = tmpList.ts_value
WHERE table.id = tmpList.id
-- AND table.id IN (1, 2, 3, .. n)
-- above "AND" is only needed if somehow you wish to limit it, i.e
-- if tmpTbl has more idsthan you wish to update
A possibly table-less (but similar) approach would involve a CASE statement, as in:
UPDATE table
SET ts = CASE id
WHEN 1 THEN 'ts_1'
WHEN 2 THEN 'ts_2'
-- ..
WHEN n THEN 'ts_n'
END
WHERE id in (1, 2, ... n) -- here this is necessary I believe
Well, without knowing what data, I'm not sure whether the answer is yes or no.
It certainly is possible to update multiple rows at once:
update table table1 set field1='value' where field2='bar'
This will update every row in table2 whose field2 value is 'bar'.
update table1 set field1='value' where field2 in (1, 2, 3, 4)
This will update every row in the table whose field2 value is 1, 2, 3 or 4.
update table1 set field1='value' where field2 > 5
This will update every row in the table whose field2 value is greater than 5.
update table1 set field1=concat('value', id)
This will update every row in the table, setting the field1 value to 'value' plus the value of that row's id field.
You could do it with a case statement, but it wouldn't be pretty:
UPDATE table
SET ts = CASE id WHEN 1 THEN ts_1 WHEN 2 THEN ts_2 ... WHEN n THEN ts_n END
I think that you should expand the context of the problem. Why do you want/need all the updates to be done in one statement? What benefit does that give you? Perhaps there's another way to get that benefit.
Presumably you are interacting with sql via some code, so certainly you can simply make sure that the three updates all happen atomically by creating a function that performs all three of the updates.
e.g. pseudocode:
function update_all_three(val){
// all the updates in one function
}
The difference between a single function update and some kind of update that performs multiple updates at once is probably not a very useful distinction.
generate the statements:
select concat('update table set ts = ts_', id, ' where id = ', id, '; ')
from table
or generate the case conditions, then connect it to your update statement:
select concat('when ', id, ' then ts_', id) from table
You can use INSERT ... ON DUPLICATE KEY UPDATE. See this quesion: Multiple Updates in MySQL
ts_1, ts_2, ts_3, etc. are different fields on the same table? There's no way to do that with a single statement.