I have a field in my database that contain comma separated values these values are numbers, and I am trying to do a search and count the number of times that a number appears in that column throughout the column,
$sql = "SELECT sector_id_csv, COUNT(sector_id_csv) as count FROM cv WHERE sector_id_csv LIKE '$sectorId'";
This seems slow and does not return any results, and I know the sector_id it is search exists in the table.
Basically, this should work fine if you use % wildcards:
WHERE sector_id_csv LIKE '%$sectorId%'";
what tends to cause problems in this scenario, though, is the fact that a search for 50 will also find 501 502 503 and so on.
If you can rely on your comma separated list to have a trailing comma behind every entry, it would be more reliable to search for
50,
to catch that value only.
WHERE CONCAT(',', sector_id_csv, ',') LIKE '%,$sectorId,%'
or
WHERE FIND_IN_SET('$sectorId', sector_id_csv);
This will ensure that your query returns only rows with sector id in given field. Provided that sector id-s in this field are comma separated.
Any query using LIKE or FIND_IN_SET will be slow as it cannot take advantage of indexes. Please consider putting all sector id-s in separate table.
Also for security reasons please remember to ensure that $sectorId is a number by casting it to int like that:
$sectorId = (int)$sectorId;
before using it in a query.
Don't you need to pad the value with the % wildcard for LIKE to work?
$sql = "SELECT sector_id_csv, COUNT(sector_id_csv) as count FROM cv WHERE sector_id_csv LIKE '%".$sectorId."%'";
At least that's my understanding from reading this article, your use of wildcards will depend on your desired condition.
...but if your scema was normalized you wouldn't need to jump through these hoops - and it would run a lot faster.
C.
Actually the number could be at he beginning or the end too. So you need to do
WHERE sector_id_csv='$sectorId' OR sector_id_csv LIKE '%,$sectorId' OR sector_id_csv LIKE '$sectorId,%' OR sector_id_csv LIKE '%,$sectorId,%'
SELECT count(*) from TABLENAME where FIND_IN_SET('VALUE',FILDNAME)>0;
Others u can use instr, regexp....
It's advisable to have FILDNAME indexed.
Related
Am using a SQL command in PHP to count the no of values inserted in a column named attack_type. I want to count the occurrence of individual values like website defacement in the whole column of the table. But here the column attack_type contain different values, separated by a comma and the count is treating whole column data as a string. Below is my current SQL statement with its output
I tried explode print_r in PHP
SELECT attack_type,
count(*) as number
FROM data_input_test
GROUP BY attack_type
Here is the output of the above statement
generated:
https://drive.google.com/open?id=1TyRL_Mh0OOJWaCpFczxmBr34No9LUpzH
But what I want is :
https://drive.google.com/open?id=1eeA_1TCER0WMpZwSkBDMzRtRa8xihbZd
and so on. The above desired output is edited to show what I exactly want.
Other answer on stackoverflow and on other forums are either irrelevant or are using regrex or a new table creation in one or the other way. That I don't want as my hosting has some limitations. My hosting doesnt provide creation of triggers, regrex or creation of temp tables
I may have a solution for this but don't know how to apply here. Possible here: https://www.periscopedata.com/blog/splitting-comma-separated-values-in-mysql
Please someone explain me how to apply the same here.
So I finally worked around to get my work done using the select only. This only works if you have a finite set of data or specifically less than 64 values.
Change your column datatype to 'set' type. And enter your set values.
Now use select, count, find_in_set and union functions of sql.
Example:
union select 'Un-patched Vulnerable Software Exploitaion'as type, count(*) as number from data_input_test where find_in_set('Un-patched Vulnerable Software Exploitaion',attack_type)```
and so on for all your values
I know this is not how you should do but as the legends say this works 😎😎
If you just want to count comma-separated values in rows, you can use:
SELECT SUM(LENGTH(attack_type) - LENGTH(replace(attack_type, ',', '')) +1) AS TotalCount
FROM table_name;
I am having a table with a column that has few ids that were put into database with multi select. Column for example contains: 1,4,5,7,9. Is it possible to check if this column contains for example number 5 or not in it through MySQL query ?.
I need to select all the people that have number 5 or some other listed in that field and print them through php.
http://dev.mysql.com/doc/refman/5.6/en/string-functions.html#function_find-in-set
SELECT ...
WHERE FIND_IN_SET(5, list_column)
But understand that this search is bound to be very slow. It cannot use an index, and it will cause a full table-scan (reading every row in the table). As the table grows, the query will become unusably slow.
Please read my answer to Is storing a delimited list in a database column really that bad?
You can use #MikeChristensen's answer to be more standard. Another trick with standard SQL is this:
select * from TableName
where ',' || ids || ',' LIKE '%,5,%'
(in standard SQL, || is the string concatenation operator, but in MySQL, you have to SET SQL_MODE=PIPES_AS_CONCAT or SET SQL_MODE=ANSI to get that behavior.)
Another MySQL-specific solution is to use a special word-boundary regular expression, which will match either the comma punctuation or beginning/end of string:
select * from TableName
where ids RLIKE '[[:<:]]5[[:>:]]'
None of these solutions scale well; they all cause table-scans. Sorry I understand you cannot change the database design, but if your project next requires to make the query faster, you can tell them it's not possible without redesigning the table.
Perhaps:
select * from TableName
where ids = '5' -- only 5
or ids like '5,%' -- begins with 5
or ids like '%,5' -- ends with 5
or ids like '%,5,%' -- 5 in the middle somewhere
It probably won't be very fast on large amounts of data. I'd suggest normalizing these multi-selection values into a new table, where each selection is a single row with a link to TableName.
select * from your_table where concat(',',target_column,',') like '%,5,%'
you can write the sql query like this, for example you are looking for the number 5
select * from your_table_name where ids='5'
if you want to check the result with php just tell me i will write it for you :)
I have 100K datas in my mysql database, I want to search a query in it. I removed stop-words and splitted it into an array of keywords and stored in a variable ie $key[0],$key[1],$key[2].I am using the following query
SELECT *
FROM `table`
WHERE (`column` LIKE '%$key1%'
OR `column` LIKE '%$key2%'
OR `column` LIKE '%$key3%');
is any other faster ways to do the same.
The only way to speed up queries like this is to use full-text searching. LIKE '%string%' can't be optimized with normal indexes, because they use B-trees that depend on matching the prefix of the string being searched for. Since your pattern begins with a wildcard, the index doesn't help.
Another solution is to normalize your database. Don't put the keywords all in one column, put them in another table, with a foreign key to this table and a row for each FK+keyword. Then you can use a join to match the keywords.
Also, you're using the wrong type of quotes around your column names. They should be backticks, not single quotes.
you can do something like this
SELECT *
FROM table
WHERE colomn REGEXP '$key1|$key2|$key3'
etc etc so instead of creating your array as a comma separated list of key words do it as a pipe separated list and then just push the string into your regex too this is simply an example
Don't SELECT *, only select what you need.
If you want to do complete-text searches, lose the % and add an index
You misspelled column
I have a database and some of the columns contain things like CA, GB etc, although some contain multiple country codes like
US+GB+CA+AU
I'm just wondering what kind of query I would do that would return that row when I'm searching for just CA or just GB, and no necessarily the whole package US+GB+CA+AU
Encase that's a little confusing, basically I just need to return that row based on a search for just CA or just GB etc.
Thanks
Use FIND_IN_SET(), but you'll first need to replace + with , since it expects a comma-separated string. Even without the
REPLACE(), this is will not make use of any index on the countrycodes column.
SELECT * FROM tbl
WHERE FIND_IN_SET('AU', REPLACE(countrycodes, '+', ',')) > 0
The proper long term solution, however, is to change your database structure to normalize these country codes into a table that contains only two columns - a country code, and the id of the associated row from the table you're attempting to query now. You can then index the column appropriately to improve performance (possibly drastically improve it).
I would recommend to normalise it like liquorvicar said.
but using SELECT ... WHERE countrycode LIKE '%GB%' would work.
http://w3schools.com/sql/sql_like.asp
It's not a good solution, but you can use LIKE for your query:
SELECT * FROM `table` WHERE `field` LIKE '%+CA+%' OR `field` LIKE 'CA+%' OR `field` LIKE '%+CA' OR `field` = 'CA'
Last two checks for firs and last values.
I need to use a query which will pull data from a field when it is less then 4 words, is this possible and if so could you give some pointers? I suppose if not possible it could cycle through the results until it found one which was 3 words and then end the while statement when it has found one.
SELECT column FROM table where LENGTH(column) - LENGTH(REPLACE(column, ' ', ''))+1 < 4
Credits and full explanation
Here Regexp Solution.
select * from TABLE where column not regexp '^.+( .+){4}$'
Calling functions in a select on a per-record basis is almost always a bad idea in terms of performance - disk space is usually much 'cheaper' than CPU capacity (I enclose that in quotes since I'm not talking about dollar costs).
Most databases tend to be "more read than write" as my DBA mentor once told me; the ideal solution in that situation is to have a trigger when inserting or updating the row to calculate the number of words in that column and store them in another column. The reason it's ideal is that the number of words only changes when you update the field, so it's better to perform the time-intensive calculation at that point rather than (unnecessarily) every time you read the record.
The added required space will be minimal since you're adding an (short) integer to a long (string) but you'll find your queries scream along by just using the integer field (make sure you index on it).
I was going to suggest a LIKE '% % % %' but I'm not entirely sure if that would work or not.