Divide one column into multiple in a new table - mysql

I have a table set up like this
id (PK) | regID (FK) | fieldID | fieldValue
There are multiple fields that can be used to enter data and which are all stored in the fieldValue column. What I'd like to do is migrate this data over to a 2nd table that looks like
regID | Name | Occupation | etc | etc
Where the columns (other than regID) are associated with fieldIDs.
I first tried populating the new table with the unique regIDs and then tried to update the rest of the row information from there based on the matching regIDs and appropriate fieldIDs but I wasn't able to get far with that.
Then I tried something like
`INSERT INTO newData(regID, pName) VALUES
((SELECT distinct regID FROM fieldData),
(SELECT fieldValue FROM fieldData WHERE fieldID= 14 ORDER BY regID))`
which obviously didn't work. I'm still thinking that the first option may be the better way, but even then I don't think it's great. Any ideas how to get this data moved over to be more organized?

you need to use case based aggregation
Here is how you do it using insert into select and case based aggregation
INSERT INTO newData(regID, pName, occupation)
select regID,
max(case when filedid=14 then fieldDate end) as pName,
max(case when filedid=15 then fieldDate end) as occupation,
.....
from fieldData
group by regID

Related

MYSQL query check if ID exist and copy column row values to another table related column names

I am trying to save Mysql row data from one database table and copy values in new database table via PhpMyAdmin but there is an issue.
My lack of knowledge is result for asking advanced users for help here. Copy, join, merge, delete or else :D ..i am really not sure what is the best method to solve this.
TABLE 1 (old) has columns: id, product_id, identifier, content
id - we dont need it for this query
post_id - (INT) which is actually related to ID in TABLE 2
identifier - (VARCHAR) different row values such as quantity, color, discount, price1, price2 which are repeatable fields
content - *(LONGTEXT) content
TABLE 2 (new) has columns:
id - (INT)
quantity - (VARCHAR)
color - (VARCHAR)
discount - (VARCHAR)
price1 - (VARCHAR)
price2 - (VARCHAR)
I need to check with mysql query does id in TABLE 2 exist compared with post_id from TABLE 1.
If does not exist skip to another record.
If exist then from TABLE 1 column called "identifier" check record names/values in rows such as quantity, color, discount, price1, price2 and copy content column values to TABLE 2 columns (names related - finded in rows of TABLE 1 column identifier.)
To simplify...Check ID from TABLE 1. If ID is good use identifier value and copy CONTENT column value from TABLE 1 to related ID and column name in TABLE 2.
You can pivot the source EAV table in a subquery using conditional aggregation, then join it with the target table for update. coalesce() can be used to handle missig attributes in the source table.
update table2 t2
inner join (
select
post_id,
max(case when identifier = 'quantity' then content end) quantity,
max(case when identifier = 'color' then content end) color,
max(case when identifier = 'discount' then content end) discount,
max(case when identifier = 'price1' then content end) price1,
max(case when identifier = 'price2' then content end) price2
from table1
group by post_id
) t1 on t1.post_id = t2.id
set
t2.quantity = coalesce(t1.quantity, t2.quantity),
t2.color = coalesce(t1.color, t2.color)
t2.discount = coalesce(t1.discount, t2.discount)
t2.price1 = coalesce(t1.price1, t2.price1)
t2.price2 = coalesce(t1.price2, t2.price2)

Return only rows where checking against multiple joined rows

I have a table called "collections" that has a comma delimited field of id's related to another table called "inspirations".
I would like to select the collection rows that contain inspirations that I can filter by a where clause. It may be easier to show an example of what I have tried:
Here is what I'm trying:
SELECT collections.id,collections.uid,title,inspids,private,collections.tstamp FROM collections
LEFT JOIN inspirations ON "%"+inspirations.id+"%" LIKE inspids
WHERE collections.uid = "54"
AND inspirations.keywords LIKE "%bright%"
This is not returning any results unless I remove the AND part. I need it to return results that match. I am probably miss-understanding LEFT JOIN, it always confuses me. The problem I'm guessing is that the LEFT JOIN is returning multiple rows, and my WHERE doesn't know how to search all of them, do I need to do a "search all left joined rows" somehow?
Or maybe there's an entirely different way to achieve this?
Thanks for any help in advance!!
As requested below by #Alpesh Jikadra:
collections table structure:
id, uid, parent, title, inspids, private, collabs, ord, tstamp
inspirations table structure:
id, uid, image, filters, caption, keywords, tstamp, thumb, stat_views, hide_from_search, ord
Example of data:
There are 1000's of rows in both tables so as an example:
inspirations has a row with id as "123" and keywords as "blabla,bright,yellow,happy", and collections has a row with inspids as "2074,123,42".
I would expect only collections with inspids of inspirations that contain "%bright%" in the keywords field to return.
Here is an SQL I used to show my problem: sqlfiddle.com/#!9/5a1f90/10
But thanks a lot to all who helped, and Daniel E for sharing the use of "find_in_set" to solve the issue, note that I had to add "GROUP BY collections.id" to only pass unique collections back, example:
SELECT collections.id,collections.uid,title,inspids,private,collections.tstamp FROM collections
LEFT JOIN inspirations ON find_in_set(inspirations.id, collections.inspids) > 0
WHERE collections.uid = "54"
AND inspirations.keywords LIKE "%bright%"
GROUP BY collections.id
You can use the function find_in_set :
SQL Fiddle
MySQL 5.6 Schema Setup:
CREATE TABLE collections (
id int,
uid int,
parent int,
title varchar(255),
inspids varchar(255),
private int,
collabs varchar(255),
ord int,
tstamp varchar(255)
);
CREATE TABLE inspirations (
id int,
uid int,
image varchar(255),
filters varchar(255),
caption varchar(255),
keywords varchar(255),
tstamp varchar(255)
);
INSERT INTO collections SET id='100', uid='12', title='A collection example', inspids='2742,123,42',private='0',collabs='',ord='0',tstamp='1523272320';
INSERT INTO inspirations SET id='2742', uid='47', keywords='blabla,bright,test';
Query 1:
SELECT collections.id,collections.uid,title,inspids,private,collections.tstamp FROM collections
LEFT JOIN inspirations ON find_in_set(inspirations.id, collections.inspids) > 0
WHERE collections.uid = "12"
AND inspirations.keywords LIKE "%bright%"
Results:
| id | uid | title | inspids | private | tstamp |
|-----|-----|----------------------|-------------|---------|------------|
| 100 | 12 | A collection example | 2742,123,42 | 0 | 1523272320 |

MySQL: Insert using results of Select field from pair clause

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

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.