MYSQL CASE THEN statement with multiple values - mysql

I am trying go select multiple values with CASE statement. I noticed we cannot do
CASE
WHEN wall.type="bk"
THEN books.id1,books.id2, // and so on
END as column_1,
Is there a way to do THEN with multiple columns or do we need to simply write a bunch of CASE THEN statements? that seems messy

No, it is just a single value. Additionally, it is contradictory to use "multiple columns" and name those multiple columns as column_1, right? :)
You can use another column to store the other id with (a similar case) and use nulls to represent the else values, just like you're doing now.
Example:
CASE
WHEN wall.type="bk"
THEN books.id1
END as column_1,
CASE
WHEN wall.type="bk"
THEN books.id2
END as column_2
Check the official documentation for more information.

No. CASE statement can only return a single value, so the only way to achieve what you want is duplicate the case ...
The database server should be optimized and perform only one time the check on the same condition ...

And everything can be done, but it always depends on what you want to do. Below I'll show you a working example right after you have to take the data as an array and do what you want.
CREATE TABLE wall (`ident` int,`type` varchar(2), `order` int);
INSERT INTO wall (`ident`, `type`, `order`) VALUES
(40,'bk', 1),
(41,'bk', 5),
(42,'rt', 2),
(43,'bk', 3),
(44,'rt', 1);
CREATE TABLE books (`ident` int,`id1` int, `time` varchar(8), `id2` int);
INSERT INTO books (`ident`, `id1`, `time`, `id2`) VALUES
(40, 10, '18:07:00', 20),
(43, 11, '05:00:00', 21),
(44, 12, '21:01:00', 22),
(41, 13, '10:00:00', 23),
(42, 14, '23:10:00', 24);
#--------------------------
SELECT
CASE
WHEN wall.type='bk'
THEN CONCAT(books.id1,'-',books.id2)
END AS column_1
FROM wall JOIN books ON books.ident = wall.ident GROUP BY wall.ident ORDER BY wall.ident ASC;
Print:
column_1
1 10-20
2 13-23
3 NULL
4 11-21
5 NULL
Solution in action via this link:
http://rextester.com/LHPI38373

According to documentation mysql_doc; you can use you can use the other syntax of case for what you wanted.
case
WHEN FIND_IN_SET(edu, "1,1st,2,2nd,3,3rd,4,4th,5,5th,pri,primary,primery") THEN
SET memEdu = "Primary";
WHEN FIND_IN_SET(edu, "intermediate,inter,f.a,fa,fac,f.a.c,f.sc,fsc,1rd year,2rd year,3rd year") THEN
SET memEdu = "Intermediate";
End case;

Related

mysql running total as view

I am still an sql greenhorn and try to convert this script, building a running total as view in mysql:
DROP TABLE IF EXISTS `table_account`;
CREATE TABLE `table_account`
(
id int(11),
account int(11),
bdate DATE,
amount DECIMAL(10,2)
);
ALTER TABLE `table_account` ADD PRIMARY KEY(id);
INSERT INTO `table_account` VALUES (1, 1, '2014-01-01', 1.0);
INSERT INTO `table_account` VALUES (2, 1, '2014-01-02', 2.1);
INSERT INTO `table_account` VALUES (4, 1, '2014-01-02', 2.2);
INSERT INTO `table_account` VALUES (5, 1, '2014-01-02', 2.3);
INSERT INTO `table_account` VALUES (3, 1, '2014-01-03', 3.0);
INSERT INTO `table_account` VALUES (7, 1, '2014-01-04', 4.0);
INSERT INTO `table_account` VALUES (6, 1, '2014-01-06', 5.0);
INSERT INTO `table_account` VALUES (8, 1, '2014-01-07', 6.0);
SET #iruntot:=0.00;
SELECT
q1.account,
q1.bdate,
q1.amount,
(#iruntot := #iruntot + q1.amount) AS runningtotal
FROM
(SELECT
account AS account,
bdate AS bdate,
amount AS amount
FROM `table_account`
ORDER BY account ASC, bdate ASC) AS q1
This is much more faster than building a sum over the whole history on each line.
The problems I cannot solve are:
Set in view
Subquery in view
I think it might be posssible to use some kind of JOIN instead of "SET #iruntot:=0.00;"
and use two views to prevent the need of a subquery.
But I do know how.
Will be happy for any hints to try.
Regards,
Abraxas
MySQL doesn't allow subqueries in the from clause for a view. Nor does it allow variables. You can do this with a correlated subquery, though:
SELECT q.account, q.b_date, q.amount,
(SELECT SUM(q2.amount)
FROM myview1 q2
WHERE q2.account < q.account OR
q2.account = q.account and q2.date <= q.date
) as running total
FROM myview1 q;
Note that this assumes that the account/date column is unique -- no repeated dates for an account. Otherwise, the results will not be exactly the same.
Also, it seems a little strange that you are doing a running total across all accounts and dates. I might expect a running total within accounts, but this is how you formulated the query in the question.

MySQL: show strings in result that were not found

I have a MySQL db table with a column containing strings. And I have a list of strings. Some of the strings from the list can be found in my table, others can't. See my table TableName:
<TableName>
IntegerColumn, StringColumn
1, one
2, two
3, three
4, four
If I execute the query
SELECT * FROM TableName WHERE StringColumn NOT IN ('three', 'four', 'five', 'six');
I get a result of two rows, which contain nothing but NULL.
How can I see for which of the strings there was no match? Because I want to add them to the db table
Thx in advance
Using the following sample
CREATE TABLE sample_table
(
id int auto_increment primary key,
details varchar(30)
);
INSERT INTO sample_table
(id, details)
VALUES
(1, 'One'),
(2, 'Two'),
(3, 'Three'),
(4, 'Four'),
(5, 'Five');
I ran the query
SELECT * FROM sample_table
WHERE details NOT IN ('two', 'three', 'nine');
which gave the correct output of:
1 One
4 Four
5 Five
If you've got NULL returned then there is something you're not explaining in your question. Can you provide schema information or even a SQL Fiddle and I'm sure you'll get a much better answer.
I think what you want is, 'three', 'four', 'five', 'six' if any of this string is not present in the database you want to identify that.
Using query I think it will be tough. You can just use below query to get the available strings and the counts. Then, if you are using a programming language you can identify which string are not present in the result and then proceed further.
SELECT StringColumn, count(*) FROM TableName group by StringColumn
Not sure if this is what you are looking for.
This should not go this way. Check the following demo to ensure that your code is correct. Now what really matters is the set of data present in the table.
DEMO
Here is the DDL:
create table tab1 (IntegerColumn int(2), StringColumn varchar(20));
insert into tab1 values(1, 'one'), (2, 'two'), (3, 'three'), (4, 'four');

How conditionally update a column that contains delimited values with ON DUPLICATE KEY UPDATE syntax

I am trying to update multiple records (about a thousand of them) using this single statement (this is a process that will run every night). The statement below only includes 3 products for simplicity:
INSERT INTO productinventory
(ProductID, VendorID, CustomerPrice, ProductOverrides)
VALUES
(123, 3, 100.00, 'CustomerPrice'),
(124, 3, 100.00, 'CustomerPrice'),
(125, 3, 100.00, 'CustomerPrice')
ON DUPLICATE KEY UPDATE
CustomerPrice = VALUES(CustomerPrice),
ProductOverrides = CONCAT_WS(',', ProductOverrides, 'CustomerPrice')
;
Everything works fine except that the ProductOverrides column gets the text 'CustomerPrice' added to it every time this statement runs, so it ends up looking like this after it runs twice:
CustomerPrice,CustomerPrice
What I want the statement to do is to add 'CustomerPrice' to the ProductOverrides column, but only if that string does not already exist there. So that no matter how many times I run this statement, it only includes that string once. How do I modify this statement to achieve that?
You can do something like this
INSERT INTO productinventory (ProductID, VendorID, CustomerPrice, ProductOverrides)
VALUES
(123, 3, 100.00, 'CustomerPrice'),
(124, 3, 100.00, 'CustomerPrice'),
(125, 3, 100.00, 'CustomerPrice')
ON DUPLICATE KEY UPDATE
CustomerPrice = VALUES(CustomerPrice),
ProductOverrides = IF(FIND_IN_SET(VALUES(ProductOverrides), ProductOverrides) > 0,
ProductOverrides,
CONCAT_WS(',', ProductOverrides, VALUES(ProductOverrides)));
Here is SQLFiddle demo

MySQL string search between commas

My db is built as follows:
value1,value2,value3 | 1
value4,value5,val"u6 | 2
value 5, value 6, value 8 |3
(Two columns, one with a key separated by commas and the other just a normal var-char)
I'm looking for the most reliable way to find a query within the quotes and I'm getting kinda lost here.
I'm using the word boundaries for that:
SELECT * FROM ABC WHERE content REGEXP '[[:<:]]value 5[[:>:]]'
The problem is when I'm doing this query:
SELECT * FROM ABC WHERE content REGEXP '[[:<:]]5[[:>:]]'
It will also return the value, which is not what I'm looking for. Another problem is that the word boundaries refer to quotes as a word boundary
How can I solve this and create a simple query that will only fetch the exact full query between the quotes?
BTW
I don't have an option to change the DB structure...
As #MarcB commented, you really should try to normalise your schema:
CREATE TABLE ABC_values (
id INT,
content VARCHAR(10),
FOREIGN KEY (id) REFERENCES ABC (id)
);
INSERT INTO ABC_values
(id, content)
VALUES
(1, 'value1'), (1, 'value2'), (1, 'value3'),
(2, 'value4'), (2, 'value5'), (2, 'val"u6'),
(3, 'value 5'), (3, 'value 6'), (3, 'value 8')
;
ALTER TABLE ABC DROP content;
Then, as required, you can perform a SQL join between your tables and group the results:
SELECT id, GROUP_CONCAT(ABC_values.content) AS content
FROM ABC LEFT JOIN ABC_values USING (id) NATURAL JOIN (
SELECT id FROM ABC_values WHERE content = 'value 5'
) t
GROUP BY id
If it is completely impossible to change the schema, you can try FIND_IN_SET():
SELECT * FROM ABC WHERE FIND_IN_SET('value 5', content)
Another workaround is to use LIKE with the delimiters of the items in your list:
WHERE content LIKE ',5,'
But the item you're looking for may be at the start or end of the list. So you have to modify the list on the fly to include the delimiters at the start and end.
WHERE CONCAT(',', content, ',') LIKE '%,5,%' -> this works for me on mysql
This works, and in some sense it's no worse than any other search that you do for an item in a comma-separated list. That's because such a search is bound to do a table-scan and therefore it's very inefficient. As the data in your table grows, you'll find it can't perform well enough to be useful.
See also my answer to Is storing a delimited list in a database column really that bad?

Insertion in Mysql, where one column has a constant value

I have a table with 2 column say C1 and C2. i need to insert 10 rows where always Columns 2 will be same.
INSERT INTO Table
(C1, C2)
VALUES
(100, 'X'),
(101, 'X'),
(102, 'X'),
(103, 'X'),
(104, 'X'),
(105, 'X'),
(106, 'X');
Is there any other way like below,
INSERT INTO Table
(C1)
VALUES
(100,102,103,104,105,106)
and value of C2 should be X for the inserted rows
Thanks in advance,
You will have to create a table
CREATE TABLE `tblA` (
`C1` INT(10) NULL,
`C2` VARCHAR(50) NULL DEFAULT 'X'
);
Then when you do INSERT INTO Table (C1) VALUES (100,102,103,104,105,106); the column C2 will have 'X' as a value.
There are, but not really very advantageous, one way or the other. If what you're trying to do is to write the constant value only once, I'd try to keep it simple and go for
SET #X := 'X'
or
SELECT #X := expression FROM ...
followed by
INSERT INTO Table
(C1, C2)
VALUES
(100, #X), (102, #X), ...;
You can apply an insert into from a select statement VALUES is hard-coded answers... insert into from select is query based insert. In the sample below, I am using #MySQL variables to create a variable "#num" and start it at 99. Then you just have to substitute per the sample as it describes... Any table that has at least the number of records you want to add. So, in my case, I am only concerned with any table that has AT LEAST 10 records. If you want to add 1000, and have a table with AT LEAST that many records, use that. The LIMIT obviously limits how many records you return from it. Since you are not really using any columns from the table, it doesn't matter what that table is. So, now the #num := #num +1 will keep increasing for every record processed, thus going to 100, 101, 102, etc for the "c1" column, and the 'X' will be constanct for the "c2" column and you are done.
INSERT INTO Table
(C1, C2)
select
#num := #num +1 as c1,
'X' as c2
from
AnyTableThatHasAtLeastNumberOfRecordsYouWant,
( select #num := 99 ) sqlvars
limit
10