Count and group non-empty values in MySQL - mysql

I need to count the non-empty (by which I mean a string containing at least 1 character) rows grouped by a particular ID. Eg. my data might look like this:
form_id mapping
1 'value_1'
1 ''
1 'value_2'
2 ''
2 NULL
3 'value_3'
and I want to count the non-empty values for each form, so I want the results to look like this:
form_id mapping_count
1 2
2 0
3 1
If the empty values were all NULL, I guess I could use
SELECT form_id, count(mapping) FROM table GROUP BY form_id
...but that would include zero-length strings in the count, which I don't want.
I could use a where clause to only return rows where a value exists in the mapping column, but I want to return the form IDs that have no mappings, so that is no good either.
I'm guessing I need a subquery of some sort, but am having trouble putting it together.

SELECT form_id, COUNT(NULLIF(TRIM(mapping), ''))
FROM mytable
GROUP BY
form_id
This will not count records that don't contains at least one non-whitespace character (this includes whitespace strings, empty strings and NULLs).
If a non-empty all-whitespace string is valid, use this:
SELECT form_id, COUNT(NULLIF(mapping, ''))
FROM mytable
GROUP BY
form_id

Related

Intersect values on Mysql comma separated values

I've a table PriceList that has a VARCHAR column tags where I store a comma separated list of values.
An example of price list is:
ID
name
tags
1
Price list 1
tag1,tag2
2
Price list 2
tag3,tag4
What I want now is to query this table passing a list of tags (comma separated values). A priceList should be selected only if all of its tags are present in the query.
The tags I pass in the query could be more than the tags defined in the PriceList's tags column.
For example:
SELECT * FROM PriceList WHERE 'tag2,tag1,tag7' IN/FIND_IN_SET??? (tags)
In this example I expect the PriceList ID1 is retrieved because all of its tags are included in 'tag2,tag1,tag7' values.
I did not find any useful function in Mysql to accomplish to what I need to do. I know this is not the best design and this is acceptable because PriceList table is really really small (5/10 items).
The only idea that came to my mind is to store tags sorted alphabetically and to see if PriceList's tag column is a substring of my tags list.
What do you think? Do you have some hint?
Have a try on the following, it splits tags in the PriceList to multiple rows and count the matching rows against the input taglist
SELECT a.ID, MAX(a.tags), MAX(a.name)
FROM (
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(p.tags, ',', comma_index), ',', -1) AS tag, p.ID, LENGTH(p.tags) - LENGTH(REPLACE(p.tags, ',', '')) + 1 AS counts, p.tags, p.name
FROM (
SELECT 1 AS comma_index
UNION ALL
SELECT 2
UNION ALL
SELECT 3
UNION ALL
SELECT 4
UNION ALL
SELECT 5
) a
JOIN PriceList p
WHERE a.comma_index <= LENGTH(p.tags) - LENGTH(REPLACE(p.tags, ',', '')) + 1
) a
WHERE FIND_IN_SET(a.tag, 'tag2,tag1,tag7')
GROUP BY a.ID
HAVING COUNT(*) = MAX(a.counts)
The UNION part is an example, make sure the running numbers are more than the maximum number of tags in the table.
http://sqlfiddle.com/#!9/eb379d/1
But be sure it is not a good design to concat tags while individual tags are still in use, consider to have a table store tags separately.

group_concat inserting double quote for empty values in mysql

I have some data stored in table as comma separated string in user_values column, so as per my requirement I want to get specific user data and values stored in user_values column should get in single quote for this purpose I am using below query and it is working fine, but if specific user doesn't have any value in user_values column then below query getting user_values with one double quote inserted however it should get empty value for that column , so how to prevent double quote if column is empty for specific user.
table
id user_values
1 1,2
2 3,4,5
3 // empty / no value for this user
4 4,7
mysql query:
case 1: if user 1 have values in user_values column then
SELECT id,GROUP_CONCAT( CONCAT("'", REPLACE(user_values,",", "','") , "'")) as user_val
FROM user
WHERE id=1;
output:
case 2: if user don't have any value then inserting double in empty column
SELECT id, GROUP_CONCAT( CONCAT("'", REPLACE(user_values,",", "','") , "'")) as user_val
FROM user
WHERE id=3;
output:
I agree with GMB's diagnosis of the issue. However, I think that NULLIF() provides a simpler solution:
SELECT id,
GROUP_CONCAT( NULLIF(CONCAT("'", REPLACE(user_values, ",", "','") , "'"), "''"
) as user_val
FROM user
WHERE id = 3 ;
I suspect the some values of user_values are empty strings (which are different than null values, that group_concat() ignores). You can work around this with a case expression within group_concat() that turns empty strings to null values, like:
SELECT
id,
GROUP_CONCAT(CASE
WHEN user_values = '' THEN NULL
ELSE CONCAT("'", REPLACE(user_values,",", "','"), "'")
END) as user_val
FROM user
WHERE id = 3;

How to check if a string in one field exist in every element of a comma separated field

I have a table which contains two fields. The first is name of type string. The second contains one or more strings separated by comma (but it can contain a single string with no commas at all)
I want to construct a query to know if the string in the name field does not exist in every comma separated strings in the names field.
Example 1:
---------------------------------------------------------
name names
---------------------------------------------------------
myname xmyname,myname,mynamey
All the comma separated strings contain the word myname. So the query shoudl not return this row.
But, Example 2:
---------------------------------------------------------
name names
---------------------------------------------------------
myname x,myname,mynamey
Should be returned. Because x does not contain myname.
The condition is that, if the string in the field name does not exists in each of the comma separated strings in the names field, then return the row.
This is not correct as this query will not return true in example 2 (which contains x which does not contain myname).
IMPORTANT NOTE:
1) There is not limit of how many commas there. It can be 0 commas or more. How to deal with this?
2) The strings are variables. It is not always the case that the string is myname. Each row contains a different string in the name field.
Try this regular expression:
where not concat(names, ',') regexp replace('^([^,]*{n}[^,]*,)*$', '{n}', name)
db-fiddle demo
How to read the pattern:
The inner pattern [^,]*{n}[^,]*, means
Any non comma character [^,] repeated any number of times (* means no times or multiple times).
followed by the value of the column name ({n} is a placeholder and will be replaced with the actual value using the replace() function)
followed by any non comma character [^,] repeated any number of times
followed by a comma
The outer pattern ^({inner_pattern})*$ means
Start of the string (^)
followed by the inner pattern repeated any number of times
followed by end of string ($)
To make this work, a comma is appended to the names column (concat(names, ',')), so that every element in the string ends with a comma.
The pattern will ensure, that any element in the comma separated string contains the value of the name column. Since you want the opposite result, we use where not ...
Assuming "myname" does not appear twice between two commas, you can count the commas and "myname"s:
where (length(names) - length(replace(names, ','))) >=
length(names) - length(replace(names, 'myname', '12345'))
This answer started off giving an incorrect REGEXP solution. But the best thing to do here would be to fix your data model, such that each name in the names column is actually on a separate row:
name | names
myname | xmyname
myname | myname
myname | mynamey
somename | x
somename | myname
somename | mynamey
Now we can do a simple aggregation query to answer your question:
SELECT name
FROM yourTable
GROUP BY name
HAVING COUNT(CASE WHEN names NOT LIKE CONCAT('%', name, '%') THEN 1 END) > 0;
Demo
You can approach this using the following SQL query
SELECT
name, names
FROM
`tablename`
WHERE
(LENGTH(names) - LENGTH(REPLACE(names, ',', '')) + 1)
=
ROUND (
(
LENGTH(names)
- LENGTH( REPLACE ( names, name, "") )
)/ LENGTH(name)
);
Explanation:-
This Will give you how many words are separated with ,
(LENGTH(names) - LENGTH(REPLACE(names, ',', '')) + 1) -
Following is matching the name in each row and returning how many times it found
ROUND (
(
LENGTH(names)
- LENGTH( REPLACE ( names, name, "") )
) / LENGTH(name)
)
DEMO

check comma separated field against comma separated value in mysql

A table field has values has 1,2,3 (comma seperated value) and a variable has 2,3. Now i need to check weather variable value is in table field using query along with another name field
user table
id name cat_id
-----------------
1 test 1,2,3
2 test1 3,4
3 test2 4
variable $value = 2, 3
Query : select * from user where name='test' and cat_id IN ('".$value."')
but for above query i get zero data
How to check if given id is exist in cat_id field and name exist in table
You can use a regex to check whether the value is contained in cat_id:
SELECT * FROM user WHERE name='test' AND cat_id REGEXP CONCAT('[[:<:]]', value, '[[:>:]]')
this will attempt to match value at any word boundary in cat_id, so for cat_id='1,2,3', values of (for example) '1,2', '2', '2,3' will match.
To put it in a string form (e.g. for PHP):
$sql = "SELECT * FROM user WHERE name='test' AND cat_id REGEXP CONCAT('[[:<:]]','" . $value. "', '[[:>:]]')";
Your cat_id field should contain only one id by row.
It's normal that your SQL request doesn't work currently because you're looking for cat_id 2 or 3 which SQL is not finding.
For example in your first row 1,2,3, for MySQL it's a string "1,2,3" and not an array of three ids.
If a name can be used by several cats maybe they should be the ones having a name_id.
And if a cat can have several names, and a name can have several cats, you should create a new table cats_names containing one name_id and one cat_id by row.

Return rows with more than one comma separated value in a string

I have a table called contacts and in that table there is a field called contact_type.
contact_type is varchar and stores comma separated values in a sting like this:
^Media^,^Historical^
However only a few rows out of thousands have more than one value stored and I need to to run a query that will return only the rows with more than one so if it stores just ^Historical^ then it will be ignored.
I’m pretty much stumped on how to build a query like this. I assume it will contain something like this:
SELECT LENGTH(#css) - LENGTH( REPLACE( #css, ',', '') ) + 1;
Basically you need to select the records where contact_type contains a comma
select * from your_table
where instr(contact_type, ',') > 0