MySQL Subselect issue - mysql

I have an issue with a mysql subselect.
**token table:**
id | token | articles
1 | 12345 | 7,6
2 | 45saf | 6,7,8
**items table:**
id | name | filename
6 | Some brilliant name | /test/something_useful.mp3
7 | homer simpson | /test/good-voice.mp3
**query:**
SELECT items.`filename`,items.`name` FROM rm_shop items WHERE items.`id` IN ( SELECT token.`articles` FROM rm_token token WHERE token.`token` = 'token')
I only get one of the two files (with the id 7 that is). What am I missing here?

For a column with concatenated data (like your "articles" column), you can not use MySQL IN() Function. Instead use the string function FIND_IN_SET() to query such values. In your case:
SELECT items.`filename`,items.`name` FROM rm_shop items
WHERE FIND_IN_SET(items.`id`,
(SELECT token.`articles` FROM rm_token token WHERE token.`token` = 'token')) > 0
A working sqlfiddle: http://sqlfiddle.com/#!2/796998/3/0

Related

MySQL string used in ORDER BY FIELD

I have an array of values stored in a single cell as a comma-separated string, thus:
"0,9,10,2,7,3,4,5,6,8,1,11,12"
I also have a table (table1) with a column (order) with these numbers in a different sequential order:
id|order
0 |5
1 |3
2 |4
3 |1
4 |2
etc
What I want to do is SELECT the "order" string from one table (table2) and use those values in an ORDER BY FIELD command when SELECTing from table1.
This should return row in this order: 3,4,1,2,0.
What I have so far is:
SELECT id
FROM table1
WHERE table1_id = 3746
ORDER BY FIELD(orderKey, (
SELECT `order` FROM table2
WHERE table2_id = 3746)
);
The problem seems to be that the SELECTorderFROM table2 is returned as a string which ORDER BY FIELD doesn't want to accept as input. It does SELECT the rows, but they are not in the specified order.
I have tried type-casting, but I may not have done this correctly. I also have sought an equivalent to a php explode function, to no avail.
MySQL version is 5.6.41
Any assistance is appreciated.
You can use FIND_IN_SET() in the ORDER BY clause:
select *
from table1
order by find_in_set(`order`, (select `order` from table2 where table2_id = 3746))
This will work if all the values in the column order of table1 exist in the string returned by the subquery as you mention in the question:
I also have a table (table1) with a column (order) with these
numbers in a different sequential order
.
See the demo.
Results:
| id | order |
| --- | ----- |
| 4 | 2 |
| 1 | 3 |
| 2 | 4 |
| 0 | 5 |
| 3 | 1 |

How to create virtual column with multiple value using MySQL SELECT?

I can add virtual columns as
SELECT '1' as id
| id |
-------
| 1 |
But I want add multiple values, example:
SELECT ('1','2','3') as id
| id |
-------
| 1 |
| 2 |
| 3 |
But this don't work
Like Marc B said in a comment you can't have a single query split a single row into multiple rows, but you can have multiple queries, each producing one of the values, by chaining them together with union.
SELECT 1 id
UNION
SELECT 2
UNION
SELECT 3
As the answer was provided in a couple of comments I'll post it as a community wiki.

activerecord ruby row with max value in mysql table

I need to select from MySQL table table1 (it's shown below) all records with different 'foreign_row_id' values and group them by maximum datetime value. For example, from the table below I should select rows with id=2 and id=3. And after this I have to join the result with table with phrase_id's.
In my project I use only Ruby and ActiveRecord without Rails.
+----+---------------------+----------------+--------------+
| id | datetime | foreign_row_id | other_fields |
+----+---------------------+----------------+--------------+
| 1 | 2013-05-02 17:36:15 | 1 | 1 |
| 2 | 2013-05-02 17:36:53 | 1 | 1 |
| 3 | 2013-05-03 00:00:00 | 2 | 3 |
+----+---------------------+----------------+--------------+
Here my ruby code:
#result= Model1.joins(:foreign_row).
where(:user_id => user_id).
order(:datetime).
reverse_order.
select('table1.*, foreign_row.*').
maximum(:datetime, :group => :foreign_row_id).
And it gives me only one record, without grouping by id and joining: {"1":"2013-05-02T17:36:53+09:00"}.
What should I change in the my code to get all rows?
I solved this by parts, first I get a SQL sentence that would solve problem:
SELECT * FROM (SELECT * FROM `models` ORDER BY `datetime` desc) m GROUP BY `foreign_row_id`
And then I built that query with Arel:
model_table = Model1.arel_table
subquery = model_table.project(Arel.sql('*')).order('`datetime` desc').as('m')
query = model_table.project(Arel.sql('*')).from(subquery).group('`foreign_row_id`')
Finally you can run that query:
Model1.find_by_sql query.to_sql
I added some back ticks because fields I tested with were SQL reserved words, I think you can omit them.

MySQL - COUNT before INSERT in one query

Hey all, I am looking for a way to query my database table only once in order to add an item and also to check what last item count was so that i can use the next number.
strSQL = "SELECT * FROM productr"
After that code above, i add a few product values to a record like so:
ID | Product | Price | Description | Qty | DateSold | gcCode
--------------------------------------------------------------------------
5 | The Name 1 | 5.22 | Description 1 | 2 | 09/15/10 | na
6 | The Name 2 | 15.55 | Description 2 | 1 | 09/15/10 | 05648755
7 | The Name 3 | 1.10 | Description 3 | 1 | 09/15/10 | na
8 | The Name 4 | 0.24 | Description 4 | 21 | 09/15/10 | 658140
i need to count how many times it sees gcCode <> 'na' so that i can add a 1 so it will be unique. Currently i do not know how to do this without opening another database inside this one and doing something like this:
strSQL2 = "SELECT COUNT(gcCode) as gcCount FROM productr WHERE gcCode <> 'na'
But like i said above, i do not want to have to open another database query just to get a count.
Any help would be great! Thanks! :o)
There's no need to do everything in one query. If you're using InnoDB as a storage engine, you could wrap your COUNT query and your INSERT command in a single transaction to guarantee atomicity.
In addition, you should probably use NULL instead of na for fields with unknown or missing values.
They're two queries; one is a subset of the other which means getting what you want in a single query will be a hack I don't recommend:
SELECT p.*,
(SELECT COUNT(*)
FROM PRODUCTR
WHERE gccode != 'na') AS gcCount
FROM PRODUCTR p
This will return all the rows, as it did previously. But it will include an additional column, repeating the gcCount value for every row returned. It works, but it's redundant data...

Combine count rows in MySQL

I've got a table in MySQL that looks roughly like:
value | count
-------------
Fred | 7
FRED | 1
Roger | 3
roger | 1
That is, it was created with string ops outside of MySQL, so the values are case- and trailing-whitespace-sensitive.
I want it to look like:
value | count
-------------
Fred | 8
Roger | 4
That is, managed by MySQL, with value a primary key. It's not important which one (of "Fred" or "FRED") is kept.
I know how to do this in code. I also know how to generate a list of problem values (with a self-join). But I'd like to come up with a SQL update/delete to migrate my table, and I can't think of anything.
If I knew that no pair of records had variants of one value, with the same count (like ("Fred",4) and ("FRED",4)), then I think I can do it with a self-join to copy the counts, and then an update to remove the zeros. But I have no such guarantee.
Is there something simple I'm missing, or is this one of those cases where you just write a short function outside of the database?
Thanks!
As an example of how to obtain the results you are looking for with a SQL query alone:
SELECT UPPER(value) AS name, SUM(count) AS qty FROM table GROUP BY name;
If you make a new table to hold the correct values, you INSERT the above query to populate the new table as so:
INSERT INTO newtable (SELECT UPPER(value) AS name, SUM(count) AS qty FROM table GROUP BY name);
Strangely, MySQL seems to do this for you. I just tested this in MySQL 5.1.47:
create table c (value varchar(10), count int);
insert into c values ('Fred',7), ('FRED',1), ('Roger',3), ('roger',1);
select * from c;
+-------+-------+
| value | count |
+-------+-------+
| Fred | 7 |
| FRED | 1 |
| Roger | 3 |
| roger | 1 |
+-------+-------+
select value, sum(count) from c group by value;
+-------+------------+
| value | sum(count) |
+-------+------------+
| Fred | 8 |
| Roger | 4 |
+-------+------------+
I was surprised to see MySQL transform the strings like that, and I'm not sure I can explain why it did that. I was expecting to have to get four distinct rows, and to have to use some string functions to map the values to a canonical form.