HAVING statement on a GROUP_CONCAT field returns no result while the condition exists - mysql

I'm having an issue with a HAVING clause on a string that is created by a GROUP_CONCAT statement.
Running the query:
SELECT row_id, GROUP_CONCAT(cell_id,'-',cell_type) AS flat_row FROM `cells`
GROUP by row_id;
returns the following:
|--------|-------------------------------------------------|
| row_id | flat_row |
|--------|-------------------------------------------------|
| 1 | 1-Text,6-Text,45-Text,5-Number,37-Text,9-Number |
However, running
SELECT row_id, GROUP_CONCAT(cell_id,'-',cell_type) AS flat_row FROM `cells`
GROUP by row_id
HAVING flat_row = '1-Text,6-Text,45-Text,5-Number,37-Text,9-Number';
returns 0 records.
I was expecting to see the same result, does anyone know why the result is empty?
The goal here is to check whether the database contains rows that have the exact cell composition provided in the HAVING clause.

The issue has been resolved. It was a combination of making sure that the order of the string was always the same on both sides of the comparison and properly escaping backslashes in the expected data. Thanks to Caius Jard and Bill Karwin for pointing me in the right direction!

Related

SQL : How to fetch data while in() clause does not work

I have a table named 'items'.
it has columns including index column such as below.
title | name | areacode
---------------------------------
police | user1 | 31,31,31
FireStation | user2 | 31,1,2
Restaurant | user22 | 1,1,0,32,32
---------------------------------
when i use below statement
select title, name from items where IN(31)
i get (police,user1) and (FireStation,user2)
However when i use IN(1)
i cannot get (FireStation, user2)
i found out that IN clause is useful when multiple values such as
IN(31,1)
are used.
But when single value such as IN(1) or IN(0), it sometimes does not fetch data correctly. I have found out CONTAINS method. however not familiar with it.
In sum, how can i fetch (FireStation, user2) if areacode contains a value '1'? or (Restaurant, user22) when areacode has a value '0'?
You should probably not be storing your area code data as CSV, because it is unnormalized and therefore will be hard to work with. That being said, MySQL has a function called FIND_IN_SET() which can check if a given value appears in a CSV string. Something like this should work:
SELECT title, name
FROM items
WHERE FIND_IN_SET('0', areacode) > 0
If you wanted to check for both the 0 or 1 area code, you could use this WHERE clause:
WHERE FIND_IN_SET('0', areacode) > 0 OR FIND_IN_SET('1', areacode) > 0

Single query for several selects -even if one select returns empty

I need to make several select statements to get simple data (only one row containing one or several fields for each select).
Simplified example:
select name, price from article where id=125
select log, email from user where uid=241
I want to process only one single statement from php side (or: I do NOT want to prepare several statements, execute several statements, catch and handle exceptions for each execution and finally fetch result for each statement...).
I tried:
select * from (
(select name, price from article where id=125) as a,
(select log, email from user where uid=241) as b
)
which works great if every subselect returns values:
name | price | log | email
------------------------------------------
dummy | 12,04 | john | john#example.com
But if one of the subselects returns empty, the whole select returns empty.
What I want is: null values for empty resulting subselects.
I tried many things with ifnull() and coalesce(), but couldn't get the awaited result (I know how to use them with null values, but I didn't find a way to deal with them in the case of an empty result set).
I finally found a solution with left joins:
select * from (
(select 1) as thisWillNeverReturnEmpty
left join (select name, price from article where id=125) as a on 1
left join (select log, email from user where uid=241) as b on 1
)
which works perfectly even if one of the subqueries returns empty (or even both, therefore the "select 1").
Another way I found on SO would be to add a count(*) in each subquery to make sure there's a value.
But it all looks quite dirty and I can't believe there's no simple way just using something like ifnull().
What is the right way to do it?
The best way I finally found was:
select * from (
(select count(*) as nbArt, name, price from article where id=125) as a,
(select count(*) as nbUser, log, email from user where uid=241) as b
)
This way, no subquery ever returns empty, which solves the problem (there's always at least a "zero" count followed by null values).
Sample result when no article is found:
nbArt | name | price | nbUser | log | email
----------------------------------------------------------------
0 | null | null | 1 | john | john#example.com

Limit number of results returned for each matching field in mysql

I'm trying to write a query that returns a fixed number of results in a group concat. I don't think it's possible with a group concat, but I'm having trouble figuring out what sort of subquery to add.
Here's what I would like to do:
Query
select id,
group_concat(concat(user,'-',time) order by time limit 5)
from table
where id in(1,2,3,4)
group by 1
When I remove the "limit 5" from the group concat, the query works but spits out way too much information.
I'm open to structuring the query differently. Specific ID numbers will be supplied by the user of the query, and for each ID specified, I would like to list a fixed number of results. Let me know if there is a better way to achieve this.
Not sure the exact result set you want, but check out this SO post:
How to hack MySQL GROUP_CONCAT to fetch a limited number of rows?
As another example, I tried out the query/solution provided in the link and came up with this:
SELECT user_id, SUBSTRING_INDEX(GROUP_CONCAT(DISTINCT date_of_entry),',',5) AS logged_dates FROM log GROUP BY user_id;
Which returns:
user_id | logged_dates
1 | "2014-09-29,2014-10-18,2014-10-05,2014-10-12,2014-10-19"
2 | "2014-09-12,2014-09-03,2014-09-23,2014-09-22,2014-10-13"
3 | "2014-09-10"
6 | "2014-09-29,2014-09-27,2014-09-26,2014-09-25"
8 | "2014-09-26,2014-09-30,2014-09-27"
9 | "2014-09-28"
13 | "2014-09-29"
22 | "2014-10-12"
The above query will return every user id that has logged something, and up to 5 dates that the user has logged. If you want more or less results form the group concat, just change the number 5 in my query.
Following up, and merging my query with yours, I get:
SELECT user_id, SUBSTRING_INDEX(GROUP_CONCAT(date_of_entry ORDER BY date_of_entry ASC),',',3) AS logged_dates FROM log WHERE user_id IN(1,2,3,4) GROUP BY user_id
Which would return (notice that I changed the number of results returned from the group_concat):
user_id | logged_dates
1 | "2014-09-16,2014-09-17,2014-09-18"
2 | "2014-09-02,2014-09-03,2014-09-04"
3 | "2014-09-10"

Iterating through MySQL rows

I have a simple MySQL table made up of words and an associated number. The numbers are unique for each word. I want to find the first word whose index is larger than a given number. As an example:
-----------------------
| WORD: | F_INDEX: |
|---------------------|
| a | 5 |
| cat | 12 |
| bat | 4002 |
-----------------------
If I was given the number "9" I would want "cat" returned, as it is the first word whose index is larger than 9.
I know that I can get a full list of sorted rows by querying:
SELECT * FROM table_name ORDER BY f_index;
But would, instead, like to make a MySQL query that does this. (The confusion lies in the fact that I'm unsure as to how to keep track of the current row in my query). I know can loop with something like this:
CREATE PROCEDURE looper(desired_index INT)
BEGIN
DECLARE current_index int DEFAULT 0
// Loop here, setting current_index to whatever the next rows index is,
// then do a comparison to check it to our desired_index, breaking out
// if it is greater.
END;
Any help would be greatly appreciated.
Try this:
SELECT t.word
, t.f_index
FROM table_name t
WHERE t.f_index > 9
ORDER
BY t.f_index
LIMIT 1
It is much more efficient to have the database return the row you need, than it is to pull a whole bunch of rows and figure out which one you need.
For best performance of this query, you will want an index ON table_name (f_index,word).
Why don't you just use MYSQL statement to retrieve the first item you found from f_index where the f_index is greater than the value your pass in.
For example :
select word from table_name
where f_index > desired_index
order by f_index
limit 1

HowTo: Query MySQL to retrieve search data, while limiting the results and sorting by a field.

I have two simple Mysql tables:
SYMBOL
| id | symbol |
(INT(primary) - varchar)
PRICE
| id | id_symbol | date | price |
(INT(primary), INT(index), date, double)
I have to pass two symbols to get something like:
DATE A B
2001-01-01 | 100.25 | 25.26
2001-01-02 | 100.23 | 25.25
2001-01-03 | 100.24 | 25.24
2001-01-04 | 100.25 | 25.26
2001-01-05 | 100.26 | 25.28
2001-01-06 | 100.27 | 30.29
Where A and B are the symbols i need to search and the date is the date of the prices. (because i need the same date to compare symbol)
If one symbol doesn't have a date that has the other I have to jump it. I only need to retrive the last N prices of those symbols.
ORDER: from the earliest date to latest (example the last 100 prices of both)
How could I implement this query?
Thank you
Implementing these steps should bring you the desired result:
Get dates and prices for symbol A. (Inner join PRICE with SYMBOL to obtain the necessary rows.)
Similarly get dates and prices for symbol B.
Inner join the two result sets on the date column and pull the price from the first result set as the A column and the other one as B.
This should be simple if you know how to join tables.
I think you should update your question to resolve any of the mistakes you made in representing your data. I'm having a hard time following the details. However, I think based on what I am seeing there are four MySQL concepts you need to solve your problem.
The first is JOINS you would use a join to put two tables together so you may select related data using the key that you describe as "id_symbol"
The second would be to use LIMIT which will allow you to specify the number of records to return such as that if you wanted one record you would use the keywould LIMIT 1 or if you wanted a hundred records LIMIT 100
The third would be to use a WHERE clause to allow you to search for a specific value in one of your fields from the table you are querying.
The last is the ORDER BY which will allow you to specify a field to sort your returned records and the direction you want them sorted ASC or DESC
An Example:
SELECT *
FROM table1
JOIN table2 ON table1.id = table2.table1_id
WHERE table1.searchfield = 'search string'
LIMIT 100
ORDER BY table1.orderfield DESC
(This is pseudo code so this query may not actually work but is close and should provide you with the correct idea.)
I suggest referencing the MySQL documentation found here it should provide everything you need to keep going.