I have a table with fields TYPES, AMOUNT and COMMENT
I want to group by the TYPES field, but if the 'TYPES' value is "other" AND 'COMMENT' is not empty, I want those records to show up separately.
Example result:
+-----------+-----------+-----------+
| types | amount | comment |
+-----------+-----------+-----------+
| type1 | 27 | |
| type2 | 65 | |
| type3 | 45 | |
| other | 4 | blabla |
| other | 8 | something |
-------------------------------------
So instead of grouping the two "other" records, I want those records to show up separately (but only if they also have a comment)
If I understand correctly, you want all rows with a given type to grouped together unless the type is 'Other' and the comment is not NULL.
A close approximation is:
select types,
(case when types = 'Other' and comment is not null
then comment end) as comment,
sum(amount) as amount
from table t
group by types,
(case when types = 'Other' and comment is not null
then comment end);
The only issue is that rows with types = 'Other' and the same comment will be grouped together. To fix this correctly, you need a unique identifier on each row, which MySQL does not readily provide.
In your case I see two separate data sets. Try with union all as below
select types, amount,comment
from tab
where (types = 'other' and comment is not null)
or types <> 'other'
group by types
union all
select types, amount,comment
from tab
where types = 'other'
and comment is null
Related
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;
I am trying to return a friend list for my users and I'm trying to gather the value matching their user_id.
| ID | user1_id | user1_status | user2_id | user2_status |
| 1 | 1 | 0 | 2 | 0 |
| 2 | 4 | 1 | 5 | 1 |
| 3 | 4 | 1 | 6 | 0 |
| 4 | 1 | 0 | 4 | 1 |
Here is the problem I have, the value I'm look for can be in either "user1_id"/"user2_id" and then I need to return the "user_status" ONLY for the other user. n. I made this table really simple. In my version there is a lot more columns I want my server to avoid returning.
Let's say that the client user_id is 4, so I need the select all the row with user1_id/user2_id equal to 4 and return the other person user_status. In the table, the first case of the value equal to 4 is in user1_id, I need that row to return the user2_id and user2_status.
Here is what I have so far, but it doesn't work:
SELECT `id`
CASE
WHEN `user1_id`='4' THEN `user2_id` AND `user2_status`
WHEN `user2_id`='4' THEN `user1_id` AND `user1_status`
ELSE NULL
END
from 'relationship'
where `user1_id`='4' OR `user2_id`='4'
How do I write this query statement?
If you refer to the CASE syntax you will see that it's defined to return a single column and not a tuple. Additionally, in your query you are trying to get either (user2_id, user_status) or NULL. Here you get a mismatch in the number of columns which is not allowed either.
If you really really want to use CASE you could do:
SELECT `id`
CASE
WHEN `user1_id`='4' THEN `user2_id`,
ELSE NULL
END
CASE
WHEN `user2_id`='4' THEN `user1_id`
ELSE NULL
END
CASE
WHEN `user1_id`='4' THEN `user1_status`
ELSE NULL
END
CASE
WHEN `user2_id`='4' THEN `user2_status`
ELSE NULL
END
FROM 'relationship'
where `user1_id`='4' OR `user2_id`='4'
yes, clunky and confusing. Much Simpler if you use UNION.
SELECT id, user2_id AS uid, user2_status as ustatus FROM relationship WHERE user1_id = 4
UNION
SELECT id, user1_id AS uid, user1_status as ustatus FROM relationship WHERE user2_id = 4
I have a mysql user table that holds user data like that:
userid | title | content
----------------------------------
1 | about | I am from ...
1 | location | Norway
1 | name | Mark
1 | website |
2 | about |
2 | location |
2 | name |
2 | website |
3 | ...
As you see the content is empty for userid 2, and also for many more users in the table.
My goal is to select only the userids that have at least 3 fields filled. All others should be ignored.
As my mysql knowledge is still weak I could not find a solution for this. I only found the opposite and just with count: Find the count of EMPTY or NULL columns in a MySQL table
What is the magic mysql query? Any help appreciated, thank you.
You would use aggregation and a having clause for this:
select u.userId
from users u
where content > '' and content is not null
group by u.userId
having count(*) >= 3;
I added the non-blank check as well as the null check. The null check is redundant, but it makes the intention clearer.
This is perhaps a fairly straight-forward SQL query, but I've not done much SQL/database querying before and have inherited an issue that I'm struggling to understand and describe properly (thus the vague title....)
USER META
======================================
id | user_id | field | value
======================================
1 | 1 | color | red
2 | 1 | year | 1923
3 | 1 | ... | ...
4 | 3 | color | purple
5 | 3 | year | 2013
6 | 3 | ... | ...
7 | 7 | color | red
8 | 7 | year | 1982
9 | 7 | ... | ...
Given that I have a table structured like the above example, how would I query for a list of user_id's filtered by a specific 'color', but sorted by 'year'?
NOTE: I'm dealing with a legacy project, so I'm not in position to make schema changes.
You can do self-join:
SELECT DISTINCT t1.user_id
FROM TableName t1
JOIN TableName t2 ON t1.user_id = t2.user_id
WHERE t1.field = 'color' AND t1.value = 'red' AND t2.field = 'year'
ORDER BY t2.value
One way is with aggregation:
select user_id
from usermeta
group by user_id
having sum((case when field = 'color' then value end) = 'purple') > 0
order by max(case when field = 'year' then value+0 end);
The having clause is counting the number of rows that meet the particular condition, and making sure there is at least one for a given user_id.
The order by is returning the year. The +0 just converts it to a numeric value, so it sorts correctly. The year is being stored as a string. (For year, this may not be important because presumably all are four digits, but for other numerics it could be important.)
I think that one solution would be to create temp tables dynamically, one with columns user_id and color and another with columns user_id and year based upon this table and then do a join on them. Even if you find a syntactically composite single statement solution, it will internally have to do something similar.
It is possible to insert into a table based upon the output of a select. Sorry, I am not giving you the exact syntax here but the direction hopefully helps.
I'm no SQL expert, but I'm not a total amateur, yet this is a query on a single table with 2 fields that I don't know how to approach.
Suppose you have a table with class # & student #. How do you find the classes that have only exactly students x, y & z?
My real problem is more like a table of catalogs & item numbers, and how to find all the catalogs that have exactly (mo more or less) the specified items.
My only thought revolved around matching on GROUP_CONCAT, but there must b731e a more elegant way...
EDIT:
I misstated the problem, so I will provide table structure as well. The issue is more like products in boxes, where a box could contain more than one of a particular product, and you want to find boxes that have exactly the specified content. So the table, for example, is:
+------------+------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+------------+------+-----+---------+----------------+
| id | bigint(20) | NO | PRI | NULL | auto_increment |
| box_id | bigint(20) | YES | | NULL | |
| product_id | bigint(20) | YES | MUL | NULL | |
+------------+------------+------+-----+---------+----------------+
I want to find all boxes that contain exactly 2 items of product ID 22, one of 17, and one of 55. No more, no less.
You could use a having clause:
select *
from YourTable
group by
class
having count(distinct student) = 3
and max(case when student = 'X' then 1 end) = 1
and max(case when student = 'Y' then 1 end) = 1
and max(case when student = 'Z' then 1 end) = 1
I do have an answer that works, but it is far from efficient OR elegant, so I present it for anyone looking for a sub-optimal but correct solution to this problem, and an enticement to anyone else to provide a better one.
SELECT box_id, GROUP_CONCAT( product_id
ORDER BY product_id DESC
SEPARATOR ',' ) AS contents
FROM box_product
GROUP BY box_id
HAVING contents = '17,22,22,55';