SQL select - include rows that don't exist? - mysql

Can someone help out with this SQL?
SELECT A.post_id, B.post_id, A.ul_value as "likes", B.ul_value as "dislikes"
FROM wp_like_dislike_counters as A,
wp_like_dislike_counters as B
where
A.post_id = B.post_id
and A.ul_key = 'u_like'
and B.ul_key = 'u_dislike'
The results I'm getting:
3, 3, 1, 2
4, 4, 3, 2
The results I want:
3, 3, 1, 2
4, 4, 3, 2
1, 1, 0, 1
Below is the data in the table. Notice that the row with id of 32 has a post_id of 1 along with 1 for the l_value (meaning 1 dislike). Since this post_id has no row for "likes", I would like to display this as a 0 as in the results I want above. Is this possible with this table structure?
id | post_id | l_key | l_value
---+---------+-----------+---------
35 | 3 | u_dislike | 2
34 | 4 | u_dislike | 2
31 | 4 | u_like | 3
32 | 1 | u_dislike | 1
36 | 3 | u_like | 1

You want to do this with conditional aggregation, not a join:
select post_id,
sum(case when ul_key = 'u_like' then ul_value else 0 end) as likes,
sum(case when ul_key = 'u_dislike' then ul_value else 0 end) as dislikes
from wp_like_dislike_counters
group by post_id;

Related

Query to calculate the count of numbers that occur in the previous rows

I have a table view like this:
Id, Picks
5, 1
5, 5
5, 10
5, 20
4, 8
4, 10
4, 11
4, 22
3, 1
3, 8
3, 10
3, 25
2, 3
2, 5
2, 23
2, 24
1, 14
1, 17
1, 20
1, 24
with two columns Id, and Picks. The id is repeated four times for each draw which has 4 numbers between 1-25.
I'd like to display the count of each draw numbers that occur in the previous 3 draws. So for the numbers of the draw with id=5, if these numbers occur once in the draws with ids 4,3, and 2, then they are counted.
So for the above example the count would be like this:
Id, Count
5, 3
4, 2
etc.
How could I get this result with a mysql query? the table view doesn't have a unique id.
I guess you need something like:
select
a.id, count(distinct b.picks)
from my_table a
join my_table b on b.picks = a.picks
and b.id between a.id - 3 and a.id - 1
group by a.id
With EXISTS:
select
t.id,
sum(
case when exists (
select 1 from tablename
where (id between t.id - 3 and t.id - 1) and picks = t.picks
) then 1
else 0
end
) counter
from tablename t
group by t.id
order by t.id desc
See the demo.
Results:
| id | counter |
| --- | ------- |
| 5 | 3 |
| 4 | 2 |
| 3 | 0 |
| 2 | 1 |
| 1 | 0 |

multi level query in sql

I want a query on 3 tables which will give me a result like below:
I've USERID depending on this I want to fetch the data from the table below:
ANSTABLE
ID | ANS | USERID | QUERYID
1 | 123 | 1 | 15
2 | 22 | 0 | 16
3 | 17 | 1 | 10
ID from ANSTABLE is mapped with ANSID in ANSVOTABLE
ANSVOTABLE
USERID | QUERYID | ANSID | UPVOTE | DOWNVOTE
3 | 15 | 1 | 1 | 0
8 | 15 | 1 | 0 | -1
7 | 15 | 1 | 0 | -1
22 | 16 | 2 | 1 | 0
QUERYID id mapped with ID from 'QUERYTABLE'
QUERYTABLE
ID | USERID | QUERY | DESCRIPTION
16 | 10 | qwerty | uytrew
15 | 11 | my_data | test_data
10 | 0 | 101010 | 101010
Now I want a result like, whenever I give USERID - 0 OR 1 etc.
it should fetch all queryID's related to entered USERID from ANSTABLE
and depending on matched queryID's all records should be returned from QUERYTABLE table and also it should give me SUM(UPVOTE)+SUM(DOWNVOTE) as total corresponding to ANSID && QUERYID from ANSVOTABLE.
In fact i want result like below
if i enter `userID - 1 it should give me by adding one more column
ID | USERID | QUERY | DESCRIPTION | ANSSCORE
15 | 11 | my_data | test_data | -1
10 | 0 | 101010 | 101010 | 0
Please note that ANSSCORE becomes -1 from the result of ANSVOTABLE by calculating upvote and downvote.
Also consider if corresponding AnsID and QueryId is not existing in ANSVOTABLE then in that case it should return me record from Querytable with o as total score
Answers will be appriciated.
You need to join those 3 tables on the keys and then do a 2 or 3rd-degree group by with whatever where clause you have as requirement.
I think this might work for you -
SELECT q.ID, q.QUERY, q.USERID, vote.UPVOTE + vote.DOWNVOTE as totalVote
FROM QUERYTABLE q
JOIN ANSTABLE ans ON ans.QUERYID = q.ID
JOIN ANSVOTABLE vote ON vote.ANSID = ans.ID
WHERE ans.USERID = 2
GROUP BY q.ID, q.QUERY, q.USERID;
You just need to sum the two columns and group by the other columns you want. You've already defined the table relationships so this should be fairly straightforward unless I'm misunderstanding something.
create table anstable(
ID number,
ANS number,
USERID number,
QUERYID number);
Insert into anstable values(1, 123, 1, 15);
Insert into anstable values(2, 22, 0, 16);
Insert into anstable values(3, 17, 1, 10);
create table ANSVOTABLE(
USERID number,
QUERYID number,
ANSID number,
UPVOTE number,
DOWNVOTE number);
Insert into ansvotable values(3, 15, 1, 1, 0);
Insert into ansvotable values(8, 15, 1, 0, -1);
Insert into ansvotable values(7, 15, 1, 0, -1);
Insert into ansvotable values(22, 16, 2, 1, 0);
create table QUERYTABLE(
ID number,
USERID number,
QUERY varchar2(50),
DESCRIPTION varchar2(50));
insert into querytable values(16, 10, 'qwerty', 'uytrew');
insert into querytable values(15, 11, 'my_data', 'test_data');
insert into querytable values(10, 0, '101010', '101010');
select a.id, a.userid, a.query, a.description, sum(b.upvote + b.downvote) as ansscore
from querytable a
join ansvotable b on b.queryid = a.id
join anstable c on c.id = b.ansid
where c.userid in (0, 1)
group by a.id, a.userid, a.query, a.description;
Results:
Table created.
1 row(s) inserted.
1 row(s) inserted.
1 row(s) inserted.
Table created.
1 row(s) inserted.
1 row(s) inserted.
1 row(s) inserted.
1 row(s) inserted.
Table created.
1 row(s) inserted.
1 row(s) inserted.
1 row(s) inserted.
Result Set 1
ID USERID QUERY DESCRIPTION ANSSCORE
15 11 my_data test_data -1
16 10 qwerty uytrew 1

Building a mysql query

I have such a base structure (short version)
Table Product:
product_id, name, status
1, Product 1, 1
2, Product 2, 1
3, Product 3, 1
4, Product 4, 1
99, Product 99, 1
Table Box:
box_id, name
1, Box 1
Table Product_To_Box:
box_id, product_id
1, 1
1, 2
1, 3
1, 4
1, 99
Table Url: (id = product_id from the table 'product')
url_id, id, url, language_id
1, 1, wp.pl, 1
2, 1, wp.pl, 2
3, 2, google.pl, 1
Table Language:
language_id, name
1, English
2, Polish
There is no problem when I need to download all the products from the table 'product', which is not present in table 'url' and are assigned a 'box_id'.
I do this query
SELECT p.product_id AS id FROM product p LEFT JOIN product_to_box p2b ON (p.product_id = p2b.product_id) WHERE NOT EXISTS (SELECT u.id FROM url u WHERE p.product_id = u.id) AND p2b.box_id = '1'
Return 3 products:
Product 3
Product 4
Product 99
However, he needs a query that will return the items as above but additionally also the products that have no connection to each language from the table 'language'
Query should return 4 products:
Product 2 - return the product because the table 'url' no entry for language_id = 2
Product 3
Product 4
Product 99
How would add another language to the table 'language', eg. Vietnam (language_id = 3) and Table 'url' would look like this
1, 1, wp.pl, 1
2, 1, wp.pl, 2
3, 2, google.pl, 1
3, 2, google.pl, 2
3, 3, google.com, 1
3, 3, google.com, 2
3, 4, onet.pl, 1
3, 4, onet.pl, 2
3, 99, interia.pl, 1
3, 99, interia.pl, 2
This query should return all products because the table 'url' there is no reference to language_id = 3
Product 1
Product 2
Product 3
Product 4
Product 99
So I think the problem with you query is the sub query "NOT EXISTS (SELECT u.id FROM url u WHERE p.product_id = u.id)". Currently your SQL query doesn't even look at the language table, so it doesn't matter if there is matching language_ids. However, if you want join all the tables together and show all product_to_box.id = 1 then the following query would work:
SELECT p.product_id AS id, url_id, url, l.name FROM product p LEFT JOIN product_to_box p2b ON (p.product_id = p2b.product_id)
LEFT JOIN url ON (p.product_id = url.id) LEFT JOIN language l ON (url.language_id = l.language_id)
WHERE p2b.box_id = '1';
This outputs the following:
+------+--------+-----------+---------+
| id | url_id | url | name |
+------+--------+-----------+---------+
| 1 | 1 | wp.pl | English |
| 1 | 2 | wp.pl | Polish |
| 2 | 3 | google.pl | English |
| 3 | NULL | NULL | NULL |
| 4 | NULL | NULL | NULL |
| 99 | NULL | NULL | NULL |
+------+--------+-----------+---------+
6 rows in set (0.00 sec)
The below SQL will show all product_id from the table 'product', that is not found in the table 'url' and do not have assigned all language_id from table 'language'. It checks to see if url.id or language_id is null.
SELECT p.product_id AS id, url_id, url, l.name FROM product p LEFT JOIN product_to_box p2b ON (p.product_id = p2b.product_id)
LEFT JOIN url ON (p.product_id = url.id) LEFT JOIN language l ON (url.language_id = l.language_id)
WHERE url.id is null or l.language_id is null;
+------+--------+------+------+
| id | url_id | url | name |
+------+--------+------+------+
| 3 | NULL | NULL | NULL |
| 4 | NULL | NULL | NULL |
| 99 | NULL | NULL | NULL |
+------+--------+------+------+
3 rows in set (0.00 sec)

Count references to own ID in MySQL with Grouping

I'm running a query on posts in a database. If the post is a response to another post, it has a parent_id greater than zero otherwise zero.
To generate a report on posts, I use the following in my SELECT and then group by user.
SELECT
SUM(IF(parent_id = 0, 1, 0)) as 'NewPosts',
SUM(IF(parent_id > 0, 1,0)) as 'Responses',
COUNT(parent_id) as 'TotalPosts',
FROM posts
GROUP BY user
Now I need to add a column that show's self responses by a user. Something like...
SUM(IF(parent_id IN id, 1, 0)) as 'SelfResponses'
Of course I know that is wrong but I hope it sends the idea across.
Edit: Data would look like :
User Id parent_id
Henry 12 0
Henry 24 12
Henry 32 16
Joseph 16 0
So in this case the output would be:
User NewPosts Responses TotalPosts SelfResponses
Henry 2 2 3 1
Joseph 1 0 1 0
Assuming for response the parentId is the postId for the response then you can achieve this by the following way
Query 1:
SELECT
a.user,
SUM(IF(a.parent_id = 0, 1, 0)) as 'NewPosts',
SUM(IF(a.parent_id > 0, 1,0)) as 'Responses',
COUNT(a.parent_id) as 'TotalPosts',
SUM(IF(a.user = b.user, 1, 0)) as 'SelfResponses'
FROM
Table1 a
LEFT JOIN
Table1 b
ON
a.parent_id = b.id
GROUP BY
a.user
Results:
| USER | NEWPOSTS | RESPONSES | TOTALPOSTS | SELFRESPONSES |
--------------------------------------------------------------
| Henry | 1 | 2 | 3 | 1 |
| Joseph | 1 | 0 | 1 | 0 |
SQL FIDDLE
Hope this helps

grouping resultset - mysql

I have the following sql which returns the total number of books grouped by status
select COUNT(BOOK_ID) AS book_num, BOOK_STATUS_FK from BOOKS group by BOOK_STATUS_FK;
+---------+------------------+
| book_num | BOOK_STATUS_FK |
+---------+------------------+
| 57 | 2 |
| 162 | 3 |
| 9736 | 4 |
| 104 | 5 |
| 29 | 22 |
| 1 | 23 |
| 5 | 25 |
| 14 | 54 |
+---------+------------------+
I would like to group the resultset into 2 rows only where one row represents the number of books with BOOK_STATUS_FK > 4 and the 2nd to represent the number of books with BOOK_STATUS_FK <= 4
Is there a way of doing that in sql?
Thanks for your suggestions.
The 2 row solution Gordon Linoff suggests wont produce 2 rows when one of the counts is 0.
The following will give both counts in a single row:
select ifnull( sum( if( book_status_fk > 4, 1, 0 ) ), 0), ifnull( sum( if( book_status_fk <= 4, 1, 0 ) ), 0 )
from books
Edit: added ifnull's
This is an aggregation with a case statement:
select (case when book_tatus_fk > 4 then '>4' else '<=4' end) as grp, count(*)
from books
group by (case when book_tatus_fk > 4 then '>4' else '<=4' end)
If you always need two rows, even if count of a group is 0, you can use palindrom's solution or you can use this slightly modified version of Gordon Linoff's query:
select grp.g, count(BOOK_STATUS_FK)
from
(select '<=4' g union all select '>4') grp left join books
on grp.g = case when book_status_fk > 4 then '>4' else '<=4' end
group by grp.g