I have a table that contain list of book. I want to count the number of row with "mysql php" in it.
If I use regular like (use the code below), it only count the row with 'mysql php'.
SELECT 'mysql php' as searched_word,
count(case when book_list like '%mysql php%' then 1 else 0 end) AS number_of_occurrences
FROM book_list
What I want is, it also count the row with "php mysql" value, but I don't have idea how to do it.
This is the table:
+------------------------+
| book_list |
+------------------------+
| mysql php for dummies |
+------------------------+
| learn php mysql |
+------------------------+
| mysql php for students |
+------------------------+
| mysql database |
+------------------------+
my expected result:
+---------------+-----------------------+
| searched_word | number_of_occurrences |
+---------------+-----------------------+
| mysql php | 3 |
+---------------+-----------------------+
Make the condition an or, and use sum() (not count()):
select
'mysql php' as searched_word,
sum(book_list like '%mysql php%' or book_list like '%php mysql%') AS number_of_occurrences
from book_list
Note the way MySQL allows briefer code to count conditions, because 'true' is '1' and 'false' is '0'.
If you wanted to count rows that had both terms somewhere, eg "learn php and mysql", use this:
sum(book_list like '%php%' and book_list like '%mysql%')
WITH
-- parse searching criteria to separate tokens (delimiter - space), remove duplicates
cte1 AS (
SELECT DISTINCT token
FROM JSON_TABLE( CONCAT('["', REPLACE(#criteria, ' ', '","'), '"]'),
"$[*]" COLUMNS( token VARCHAR(254) PATH "$" )
) AS jsontable
),
-- select books which' title contains ALL tokens as complete words
-- words delimiter - space
-- commas, dots and another punctuation is NOT removed
cte2 AS (
SELECT book_list.book_list
FROM book_list
JOIN cte1 ON LOCATE(cte1.token, REPLACE(book_list.book_list, ' ', CHAR(0)))
GROUP BY book_list.book_list
HAVING COUNT(*) = ( SELECT COUNT(*)
FROM cte1 )
)
-- count the amount of matched titles
SELECT #criteria searched_word, COUNT(*) number_of_occurrences
FROM cte2;
fiddle
PS. Needed MySQL 8.0.4 or newer.
Related
I am attempting to get a query that was previously used with MySQL to work with H2. The query does exactly as needed in MySQL (when the double quotes are replaced with backticks). It is as follows:
SELECT GROUP_CONCAT(DISTINCT "Id" ORDER BY "Id" SEPARATOR ' ') "Id",
GROUP_CONCAT(DISTINCT "Course" ORDER BY "Id" SEPARATOR ' ') "Course",
GROUP_CONCAT("Day/s" ORDER BY "Id" SEPARATOR ' ') "Day/s",
"Sect",
"Class Nbr"
FROM SAMPLE
GROUP BY "Class Nbr", "Sect"
The query in reality is programmatically generated, but that example captures what its purpose. Yes I am aware that using quotes around all column and table names to accommodate potential spaces is not ideal, but it is the approach that I have to work with at the moment.
The problem is that H2 does not seem to be interpreting the DISTINCT keyword, at least not like how MySQL was interpreting it. In H2, it is concatenating all aggregated values, regardless of whether they are distinct. For example, following the above example query, two duplicate Id entries get concatenated, which is not the behavior that I would like.
Running the aforementioned SELECT query on the following table setup illustrates the problem:
CREATE TABLE SAMPLE("Id" VARCHAR(255), "Course" VARCHAR(255), "Day/s" VARCHAR(255), "Sect" VARCHAR(255), "Class Nbr" VARCHAR(255));
INSERT INTO SAMPLE VALUES (1, 'class1', 'M W F', 1134, 553);
INSERT INTO SAMPLE VALUES (2, 'class1', 'T R', 1134, 553);
INSERT INTO SAMPLE VALUES (3, 'class2', 'T R', 1111, 444);
The result is:
Id | Course | Day/s | Sect | Class Nbr
---------------------------------------
3 | class2 | T R | 1111 | 444
---------------------------------------
1 2 | class1 class1 | M W F T R | 1134 | 553
Whereas I'd like the result to be, as it was in MySQL:
Id | Course | Day/s | Sect | Class Nbr
---------------------------------------
3 | class2 | T R | 1111 | 444
---------------------------------------
1 2 | class1 | M W F T R | 1134 | 553
Any help porting this query over to H2 would be greatly appreciated.
This is a bug in H2 1.4.200 and older versions, DISTINCT does not work in ordered aggregate functions (ARRAY_AGG, LISTAGG, and vendor-specific aliases for LISTAGG) if whey have an ORDER BY clause.
It was fixed and the fix will be included into H2 1.4.201.
To get the fix now you can download the current sources on GitHub:
https://github.com/h2database/h2database
Use a build script with a jar target as described here:
https://h2database.com/html/build.html#building
Don't use a Maven build of H2, it is experimental only and it does not produce the fully-featured jar.
I'm not sure how is your engine interpreting your sql syntax. But what I can see is that you grouping is based on aggregated column "Class Nbr". Try remove this.
Using MySQL GROUP_CONCAT: (see dbfiddle)
SELECT GROUP_CONCAT(DISTINCT `Id`ORDER BY `Id` SEPARATOR ' ') `Id`
, GROUP_CONCAT( `Course` ORDER BY `Id` SEPARATOR ' ') `Course`
, GROUP_CONCAT( `Day/s` ORDER BY `Id` SEPARATOR ' ') `Day/s`
, `Sect`
, GROUP_CONCAT(DISTINCT `Class Nbr` ORDER BY `Id` SEPARATOR ' ') as `Class Nbr`
FROM `sample_sheet_Copy`
GROUP BY `Sect`
Using ListAgg with Distinct:
SELECT LISTAGG( "Id", ' ' DISTINCT) WITHIN GROUP (ORDER BY "Id") "Id"
, LISTAGG("Course", ' ') WITHIN GROUP (ORDER BY "Id") "Course"
, LISTAGG("Day/s", ' ') WITHIN GROUP (ORDER BY "Id") "Day/s"
, "Sect"
, LISTAGG("Class Nbr", ' ' DISTINCT) WITHIN GROUP (ORDER BY "Id") as "Class Nbr"
FROM "sample_sheet_Copy"
GROUP BY "Sect"
I am using MySQL 5.x, and am trying to come out with a SQL statement to select rows base on the following datasets
ID | Type | Name
1 | Silver | Customer A
2 | Golden | Customer B
3 | Silver, Golden | Customer C
4 | Bronze, Silver | Customer D
I need to use regexp (Legacy system reasons) in the SQL statement, where I need to only select ID=1 and ID=4, which means I need "Silver", "Silver with Bronze" customer type, but not "Silver + Golden"
I am not very familiar with regular expressions, been trying with SQL like below:
SELECT DISTINCT `customer_type` FROM `customers` WHERE
`customer_type` regexp
"(Silver.*)(^[Golden].*)"
Where I need to have the regular expressions in one place like above, but not like below:
SELECT DISTINCT `customer_type` FROM `customers` WHERE
`customer_type` regexp
"(Silver.*)"
AND NOT
customer_type` regexp
"(Golden.*)"
Although LIKE will work, but I can't use it for special reasons.
SELECT DISTINCT `customer_type` FROM `customers` WHERE
`customer_type` LIKE "%Silver%"
AND NOT
customer_type` LIKE "%Golden%"
I couldn't get the first SQL statement to work, and not sure even if that is possible.
Just try these one:
SELECT DISTINCT `id`, `customer_type`
FROM `customers`
WHERE `customer_type` regexp "^.*Silver$"
This matches "anything + Silver" or just Silver.
Maybe answer is very easy, but I can't find the right MySQL query which do what I want.
I have table user :
| id_user | name | action_type |
+---------------------------------+
| 1 | joshua | 1,13,12,40 |
| 2 | joshua | 2,8 |
And I want to select only rows which have exact number in action_type column.
action_type is stored in MySQL as TEXT.
I've tried this:
SELECT * FROM user WHERE action_type LIKE '%2%'
But it selected rows with 12 which is not what I want :(
Maybe it's possible with IN operator, but I couldn't find a right way to use this.
You are looking for FIND_IN_SET
SELECT *
FROM user
WHERE FIND_IN_SET( '2', action_type )
SQL Fiddle DEMO
UPDATE
Just to mentioned it, this is also possible
SELECT *
FROM user
WHERE FIND_IN_SET( 2, action_type )
MySQL will do an automatic conversion to char
Include the delimiter in your LIKE clause:
SELECT *
FROM user
WHERE action_type LIKE '2,%'
OR action_type LIKE '%,2,%'
OR action_type LIKE '%,2'
Note that I had to use two additional LIKE clauses to cover the cases where the item is at the beginning or end of the string.
Try
SELECT * FROM user
WHERE CONCAT( ',', action_type, ',' ) LIKE '%,2,%';
correct syntax from Sir Rufo
I have a table which stores information of a lot of twitter tweets including the tweet text and the screen name of the user who tweeted the tweet. The tweets contain hashtags (starting with #), I want to count the number of hashtags that a specific user has tweeted:
tweet_id | tweet_text | screen_name |
--------------------------------------------------------------------------------------------
1 | #hashtag1 #otherhashtag2 #hashtag3 some more text | tweeter_user_1 |
2 | some text #hashtag1 #hashtag4 more text | tweeter_user_2 |
3 | #hashtag5 #hashtag1 #not a hashtag some#nothashtag | tweeter_user_1 |
4 | #hashtag1 with more text | tweeter_user_3 |
5 | #otherhashtag2 #hashtag3,#hashtag4 more text | tweeter_user_1 |
If I were to count the hashtags of tweeter_user_1, the result i expect is 8, if i wanted the hashtags of tweeter_user_3 it should return 1. How can I do it assuming that my table name is tweets.
I tried this: SELECT COUNT( * ) FROM tweets WHERE( LENGTH( REPLACE( tweet_text, '#%', '#') = 0 ) ) AND screen_name = 'tweeter_user_1' but it didn't work
I would be happy if the result of tweeter_user_1 was 9 too :D
This should give you a list of screen_names and the total count of all hashtags they use.
SELECT foo.screen_name, SUM(foo.counts) FROM
(
SELECT screen_name,
LENGTH( tweet_text) - LENGTH(REPLACE(tweet_text, '#', '')) AS counts
FROM tweet_table
) as foo
GROUP BY foo.screen_name
But.... it's a nasty query if the table is huge. I might specify a specific users in the inner select if you just need counts for a single user. Like this:
SELECT foo.screen_name, SUM(foo.counts) FROM
(
SELECT screen_name,
LENGTH( tweet_text) - LENGTH(REPLACE(tweet_text, '#', '')) AS counts
FROM tweet_table WHERE screen_name = 'tweeter_user_1'
) as foo
GROUP BY foo.screen_name
Depending on how often you need to run the query, you could be causing MySQL to spend a lot of CPU time parsing and reparsing the tweet_text column. I would strongly recommend adding a hashtag_qty column (or similar) and store the count of hashtag elements there when you populate the row to begin with.
I have a problem with sql query in php:
select
user, name, outlet, switch, port, vlan, mac, status
from access where
user like '%'
and name like '%'
and outlet like '%'
and switch like '%'
and port like '%'
and vlan like '%'
and mac like '%'
and status like '%'
order by 'user';
When running query on MySQL client version: 5.1.36 query doesn't work totally (ORDER BY won't work), however when running SAME query on MySQL client version: 4.1.13, ORDER BY works!
I have checked nearly all manuals about ORDER BY, WHERE, LIKE commands, but no result. No mention about version differences, etc..
You have to remove the quotes from user in the ORDER BY clause. This is what is causing the ORDER BY not working as expected, because you can use any expression in the ORDER BY clause, and the 'user' in quotes is being considered an expression (constant) instead of a column name.
Test case (MySQL 5.1.45):
CREATE TABLE tb (id int);
INSERT INTO tb VALUES (5);
INSERT INTO tb VALUES (1);
INSERT INTO tb VALUES (4);
INSERT INTO tb VALUES (2);
INSERT INTO tb VALUES (3);
SELECT * FROM tb ORDER BY 'id';
+------+
| id |
+------+
| 5 |
| 1 |
| 4 |
| 2 |
| 3 |
+------+
5 rows in set (0.00 sec)
SELECT * FROM tb ORDER BY id;
+------+
| id |
+------+
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
+------+
5 rows in set (0.00 sec)
I think what you need is:
SELECT `user`,`name`,`outlet`,`switch`,`port`,`vlan`,`mac`,`status`
FROM `access`
WHERE `user` like '%'
AND `name` like '%'
AND `outlet` like '%'
AND `switch` like '%'
AND `port` like '%'
AND `vlan` like '%'
AND `mac` like '%'
AND `status` like '%'
ORDER BY `user`;
Though I don't understand your WHERE clause. It doesn't filter on any of the fields.
EDIT; some of your column names (user, name, port and status) could be MySQL keywords. Try enclosing them in grave accents (`) (I added them to my post as well).