I have a record table and its comment table, like:
| commentId | relatedRecordId | isRead |
|-----------+-----------------+--------|
| 1 | 1 | TRUE |
| 2 | 1 | FALSE |
| 3 | 1 | FALSE |
Now I want to select newCommentCount and allCommentCount as a server response to the browser. Is there any way to select these two fields in one SQL?
I've tried this:
SELECT `isRead`, count(*) AS cnt FROM comment WHERE relatedRecordId=1 GROUP BY `isRead`
| isRead | cnt |
| FALSE | 2 |
| TRUE | 1 |
But, I have to use a special data structure to map it and sum the cnt fields in two rows to get allCommentCount by using an upper-layer programming language. I want to know if I could get the following format of data by SQL only and in one step:
| newCommentCount | allCommentCount |
|-----------------+-----------------|
| 2 | 3 |
I don't even know how to describe the question. So I got no any search result in Google and Stackoverflow. (Because of My poor English, maybe)
Use conditional aggregation:
SELECT SUM(NOT isRead) AS newCommentCount, COUNT(*) AS allCommentCount
FROM comment
WHERE relatedRecordId = 1;
if I under stand you want show sum of newComments Count and all comments so you can do it like
SELECT SUM ( CASE WHEN isRead=false THEN 1 ELSE 0 END ) AS newComment,
Count(*) AS AllComments From comments where relatedRecord=1
also you can make store procedure for it.
To place two result sets horizontally, you can as simple as use a subquery for an expression in the SELECT CLAUSE as long as the number of rows from the result sets match:
select (select count(*) from c_table where isread=false and relatedRecordId=1 ) as newCommentCount,
count(*) as allCommentCount
from c_table where relatedRecordId=1;
On my current project I have something like the following tables.
Customer table Task table
+----+----------------+ +----+--------------+-------------+
| id | name | | id | description | customer_id |
+----+----------------+ +----+--------------+-------------+
| 1 | teste client 1 | | 1 | do something | 1 |
+----+----------------+ +----+--------------+-------------+
| 2 | teste client 2 | | 2 | anything | 2 |
+----+----------------+ +----+--------------+-------------+
And i want to search by task description and customer name using some user keywords.
select *
from task t
inner join customer c on t.customer_id = c.id
where match(t.description, c.name)
against ('+test*+some*' IN BOOLEAN MODE);
Using the previous query i'm getting the following error Error Code: 1210. Incorrect arguments to MATCH, i know that i can not use fields from diferent tables in the same match.
But how can i have the exact same results as the previous query using more that one match?
(If someone have or knows a good article about this kind of problems, please let me know)
Updates
Follow some exptected results for the provided query and data:
when I search by test and somethe result should be only teste client 1
when I search by test and client the result should be teste client 1 and teste client 2
when I search by any the result should be teste client 2
You can check the expected result in the SQLFiddle if for example we have only one table with both name and description.
UPDATED solution SQLFiddle
set #q = 'test* some*';
select * from
(
select
c.id,
c.name,
match(c.name) against (#q IN BOOLEAN MODE) as t1_match,
match(t.description) against (#q IN BOOLEAN MODE) as t2_match
from task t
inner join customer c on t.customer_id = c.id
) as s
where s.t1_match > 0 OR s.t2_match > 0
Currently, I think your desired results logic is mutually exclusive. See my comment above.
I have a table [mapping] with 2 columns similar to below
id | values
1 | 1,2
2 | 1,2,3
3 | 1,1
4 | 1,1,2
and another table [map] is similar to this
sno | values
1 | Test
2 | Hello
3 | Hai
My expected output is
id | values
1 | Test,Hello
2 | Test,Hello,Hai
3 | Test,Test
4 | Test,Test,Hello
Is it possible? If it is please can anybody build a query for me.
You can use MySQL FIND_IN_SET() to join the tables and GROUP_CONCAT() to concat the values :
SELECT s.sno,GROUP_CONCAT(s.values) as `values`
FROM mapping t
INNER JOIN map s ON(FIND_IN_SET(s.id,t.values))
GROUP BY s.sno
Note: You should know that this is a very bad DB structure. This may lead to a lot more complicated queries and will force you to over complicate things. You should Normalize your data, split it , and place each ID in a separate record!
SELECT
`ids`.`id`,
GROUP_CONCAT(`values`.`texts`) AS texts
FROM
`ids`
INNER JOIN `values` ON FIND_IN_SET(`values`.`id`, `ids`.`values`)
GROUP BY
`ids`.`id`
It works like this: Example
I have to make a SQL query in Mysql to search a string list (for ex: 1,2,3) in a columns (for ex: list_id), which also have string value list (1,2,3).
For more detail, my_table is
+-----------+----------+
| id | list_id |
+-----------+----------+
| 1 | 29 |
| 2 | 30 |
| 3 | 31 |
| 4 | 4,5,6,7 |
| 5 | 8,9,10,11|
| 6 | 4,5,8,9 |
| 7 | 1,2,3,6 |
+-----------+----------+
The search value is 1,5,8 and I need get the rows have list_id have 1 or 5 or 8 in it's list. Therefore, the result wil be:
+-----------+----------+
| id | list_id |
+-----------+----------+
| 4 | 4,5,6,7 |
| 5 | 8,9,10,11|
| 6 | 4,5,8,9 |
| 7 | 1,2,3,6 |
+-----------+----------+
My query string is:
SELECT * FROM my_table
WHERE list_id LIKE '%,1,%'
OR list_id LIKE '1,%'
OR list_id LIKE '%,1'
OR list_id LIKE '%,5,%'
OR list_id LIKE '5,%'
OR list_id LIKE '%,5'
OR list_id LIKE '%,8,%'
OR list_id LIKE '8,%'
OR list_id LIKE '%,8'
It is match correct what I want. However, the length of query is in proportion to length of list.
Does REGEXP is better than LIKE in this circumstance?
Does anyone have experience to make another solution better?
You may try to concatenate commas to your field (or use SET in MySQL or make a better database structure - in which you join on tables in which the related data is stored).
SELECT * FROM yourtable WHERE CONCAT(',', fieldname, ',') like '%,1,%';
Yes, regular expressions will work for this. Here is what you can do:
SELECT * FROM junk
WHERE CONCAT(',', list_id, ',') REGEXP CONCAT(',(', REPLACE('1,3,8',',','|'), '),');
Results:
ID | LIST_ID
5 | 8,9,10,11
6 | 4,5,8,9
7 | 1,2,3,6
Please see SQL Fiddle demo here.
We turn the query list 1,3,8 into an alternating group 1|3|8. You might be able to do this in your application code to avoid using the REPLACE() function above.
UPDATE Apologies, I mistakenly used 1,3,8 as the query parameter instead of 1,5,8. But it should still work.
I am going to strongly suggest that you change the design of the database (I am assuming you have some control or influence over it).
You should make the id column non-unique and then the list_id column should contain a single value. You can then search as follows:
SELECT id WHERE list_id IN (1,5,8)
If it is a big table and there are a lot of list_id values, put an index on the list_id column.
If you need the output in a comma-separated list, then you will need to use an aggregating concatenation function with GROUP BY (e.g., GROUP_CONCAT() in MySQL).
If you cannot change the design of the schema, then use one of the other suggestions here.
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.