MySQL: Insert using results of Select field from pair clause - mysql

I've got a requirement to add an additional item of data to an existing row and insert the result in a second table. The data item is different for each row I am selecting, so I can't just add it to the SELECT statement. The original query is:
SELECT player_id,token_id,email FROM players
WHERE token_id in (101,102) OR email in ("test4#test.com");
I'd like to be able to do something like a Row Constructor and write the query something like this:
SELECT player_id,token_id, email, key_val FROM players
WHERE (token_id, key_val) in ( (101, 'xyz'),(102,'abc'))
OR (email, key_val) in ( ("test4#test.com", 'qpr') );
So that the second value ('key_val') from the pair in the IN clause would be added into the SELECT output as the last column. And then the whole lot will get inserted into the final table.
The number of items in the IN clause will vary from 3 to potentially 100's.
Really sorry if this is a dup. I've looked up things like:
Select Query by Pair of fields using an in clause
MySQL: How to bulk SELECT rows with multiple pairs in WHERE clause
I guess I could use a temporary table but I'm concerned about the number of times that this is going to be called.
Edit--
To clarify, the source table is something like:
player_id, token_id, email
===================================
1 101 null
2 102 null
3 null test4#test.com
and the date being supplied is:
(token_id=101, key_val='xyz'),(token_id=102, key_val='abc'),(email='test4#test.com', key_val='qpr')
and the intended output would be:
player_id token_id email keyy_val
========== ========= ============== ========
1 101 null zyz
2 102 null abc
3 null test4#test.com qpr
Hope this makes it clearer.

try this
SELECT player_id,token_id, email, key_val
FROM players
WHERE token_id in (101,102) AND key_val IN ('xyz','abc')
OR ( email in ("test4#test.com") AND key_val IN ('qpr') );
EDIT -.
try this
SELECT player_id,token_id, email, key_val
FROM ( select player_id,token_id, email,
if(`token_id` =101 , 'xyz',
if(`token_id` =102 , 'abc' ,
if(email = "test4#test.com" , 'qpr' , NULL))
) key_val
from players
)p
DEMO SQLFIDDLE

Related

SQL: Joining 3 tables to generate report dashboard

I am trying to join 3 different tables that holds my test execution results as "PASS", "FAIL" and "SKIP". There are 2 common properties in these 3 tables on the basis of which I need to club my result i.e. "BUILD_NUMBER" and "COMPONENT".
Tried several approach but does not get the desired result.
Best result reached so far.
Sample query:
select test_execution.COMPONENT, test_execution.BUILD_NUMBER,
count(test_execution.TEST_STATUS) as PASS from (test_execution
INNER JOIN test_execution_fail ON
test_execution.BUILD_NUMBER = test_execution_fail.BUILD_NUMBER) group by
COMPONENT,BUILD_NUMBER;
My tables look like below:
CREATE TABLE test_execution_skip (
BUILD_NUMBER int,
TEST_NAME varchar(255),
TEST_CLASS varchar(255),
COMPONENT varchar(255),
TEST_STATUS varchar(255)
);
Other two tables are exactly same with test_execution and test_execution_fail as their names.
test_execution table holds 3 records(all pass values), test_execution_fail table holds 2 records (all fail values) and test_execution_skip table holds 1 record(skip value).
I want to populate data that will show me BUILD_NUMBER, COMPONENT, TOTAL, PASS, FAIL, SKIP as records where TOTAL, PASS, FAIL and SKIP will show the respectives counts.
Any help is appreciated here.
Not sure if this answers your question but you could try something like this
WITH cte AS (
SELECT * FROM test_execution
union
SELECT * FROM test_execution_fail
UNION
SELECT * FROM test_execution_skip
)
SELECT t.*, (SKIP + FAIL + PASS) AS TOTAL FROM (
select
COMPONENT,
BUILD_NUMBER,
SUM(IF(TEST_STATUS = 'skip', 1, 0 )) as SKIP,
SUM(IF(TEST_STATUS = 'fail', 1, 0 )) as FAIL,
SUM(IF(TEST_STATUS = 'pass', 1, 0 )) as PASS
FROM cte
group by COMPONENT,BUILD_NUMBER
)t
db fiddle

SQL: Return immediately if one matched record found

I have one table with user and their posts. It looks like "user_id | post_id | post_status".
Now I have a list of userid (ex, 100 users) and I want to know how many of them has at least one post that gets deleted (ex, post_status 3).
Here is my sample search:
select count(distinct user_id)
from post_table
where user_id in ( {my set} )
and post_status=3
It runs super slow since it iterates the entire table. Is there a way to speed up the query?
Use something like
SELECT COUNT(*)
FROM
-- the list of userid as a rowset
( SELECT 123 AS user_id UNION ALL
SELECT 456 UNION ALL
-- ...
SELECT 789
) user_id_list
WHERE EXISTS ( SELECT NULL
FROM post_table
WHERE post_table.user_id = user_id_list.user_id
AND post_table.post_status = 3 )
If your MySQL version is 8.0.4 or above then you may provide the users list as CSV/JSON and parse it using JSON_TABLE (the query text will be more compact).
INDEX(post_status, user_id)
may help speed up your query, especially if very few rows have status=3.
This could also speed up Akina's solution.

How could I get a list of unique records from below duplicated records by ignoring first two characters?

Here is the rule:
When comparing userId, only search userId starting with 'AB' and its matching duplicates (except 'AB'). Then get a list of "unique userId" by only returning above duplicated userId that is having 'AB' at the beginning.
For returned duplicated string starting with 'AB', we need to make sure there is "duplicate"; otherwise, we should not return 0 record
I know it sounds confusing, please see example below:
Table UserName with ten records, and its userId fields (10 records) are:
ABC1234
C1234
C12345
BC12345
BBC1234
ABF1235
F1235
ABY1236
BCD3456
D3456
Desired Result after running query:
ABC1234
ABF1235
Please note: Although ABY1236 starts with 'AB', this record should not be returned in output, since it doesn't have a "duplicate" match like Y1236 (ignoring first two character, 'AB').
I have a sample query below, but it only returned duplicated record NOT starting with 'AB', also it will return ABY1236.
SELECT distinct substr(userId , -(length(userID)-2))
from UserName where userId like 'AB%';
Thanks for the help!
You can use EXISTS to check if there is a userId that is equal to the right part of "AB.." starting from the 3d char:
select u.userId from UserName u
where
u.userId like 'AB_%'
and
exists (
select 1 from UserName where userId = substr(u.userId, 3)
)
You could try using a selct join for check only the matching result
SELECT substr(a.userId , -(length(a.userID)-2))
from UserName a
INNER JOIN UserName b ON a.substr(a.userId , -(length(a.userID)-2)) = b.UserId
AND userId like 'AB%'

Insert multi column result into single column table

I have a table 'movies' with three Columns: 'id', 'master_id' and 'searchMe' (simplified). I have another Table 'temp_ids' with a single column: 'id'. It is a temporary table, but I don't think that matters.
When I make a query on my table 'movies' like
SELECT `id`, `master_id` FROM 'movies' WHERE searchMe = '1';
I get a multi column result. Now I want to insert every id and every master_id into the 'temp_ids'-Table, but one at a time. So if my result is
id_1 | master_1
id_2 | master_2
id_3 | NULL
I want my temp_ids to look like
id_1
master_1
id_2
master_2
id_3
So I want to convert every single column in the result into its own row. How can I do that in an elegant way?
I know I can do it in multiple queries, searching for id and master_id separatly, and I know I can solve that problem with PHP or so. But I would prefer it to solve that problem in a single mysql-query, if such a thing is possible.
I made a sqlfiddle for this:
http://sqlfiddle.com/#!2/b4a7f/2
To SELECT the data you can use a UNION ALL for this:
SELECT `id`
FROM movies
WHERE searchMe = 1
union all
SELECT `master_id`
FROM movies
WHERE searchMe = 1
and master_id is not null
see SQL Fiddle with Demo
Doing it this way, you cannot distinguish between what value comes from each column, so you can always add an indicator, this will give you two columns but then you know where the data came from:
SELECT `id`, 'id' type
FROM movies
WHERE searchMe = 1
union all
SELECT `master_id`, 'master'
FROM movies
WHERE searchMe = 1
and master_id is not null
Then you would just use this query to INSERT INTO temp using this SELECT
It would be like this
INSERT INTO temp_ids(id)
SELECT id
FROM
(
SELECT id
FROM FirstTable
UNION
SELECT master AS id
FROM SecondTable
) t

if else in mysql query

Let's say that I want to insert a record in a table. Each record has an ID (not unique)
I want to check two columns (let say first and last name) and if these columns have already been in my table use that id, unless use another id for the new record.
In other words, I want to say IF the name is new assign a new ID else assign the id of that record. (Don't worry about the new id, assume that I have an original id for each record)
For example let say I have the following records in my table:
FirstName | LastName | Location | Age ... | ID
John | Smith | Canada | 12 ... | 1234
John | Smith | US | 21 ... | 1234
And now I want to add another John Smith. So I want the same ID for the new record. While if I want to add Paul Smith, I want a new ID for that.
INSERT INTO YourTable (FirstName, LastName, Location, ID)
SELECT new.FirstName, new.LastName, new.Location, IFNULL(present.ID, new.ID)
FROM
(SELECT 'John' AS FirstName
, 'Smith' AS LastName
, 'UK' AS Location
, 1111 AS ID) AS new
LEFT OUTER JOIN YourTable AS present
ON present.FirstName = new.FirstName
AND present.LastName = new.LastName
ORDER BY present.ID DESC
LIMIT 1;
SQLFiddle
You can use IFNULL to get the current value or use a new one, when that one is missing.
INSERT INTO your_table (id, first_name, last_name, other_stuff) VALUES (
( SELECT IFNULL (
( SELECT id FROM your_table WHERE first_name = 'John' AND last_name = 'Doe'),
'new_id'
),
),
'John',
'Doe',
'Your other data'
)
Though it does sound to me that you are trying to assign a unique id for every first/last name combination. Depending on your use case there may be better ways to do that (if I am right) like, keep the id <-> name mapping in a separate table for example, and only use the id in the table that you are referring to in this post.
INSERT .... ON DUPLICATE KEY UPDATE
You can also specify a different action for duplicate keys to suit your needs.
I believe the fields you are checking against need to be indexed to work.
Hope that helps.
CASE WHEN EXISTS (SELECT * FROM `names` WHERE `first`=$first AND `last`=$last) THEN (SELECT MAX(`id`) FROM `names` WHERE `first`=$first AND `last`=$last) ELSE $new_id
...is the closest literal answer to your question. However, in your case, this might be better:
IFNULL(SELECT MAX(`id`) FROM `names` WHERE `first`=$first AND `last`=$last, $new_id)
CASE WHEN is an actual if-then-else structure, whereas IFNULL (or equivalently, COALESCE) just provides a default if nothing is found.