I have a table like this structure:
| event id | item 1 id | item 2 id | set |
| 1 | 1 | 2 | 1 |
| 1 | 1 | 3 | 1 |
| 1 | 2 | 1 | 1 |
| 1 | 2 | 3 | 1 |
| 1 | 3 | 1 | 1 |
| 1 | 3 | 2 | 1 |
| 1 | 2 | 4 | 2 |
| 1 | 4 | 2 | 2 |
| 2 | 1 | 4 | 3 |
| 2 | 1 | 5 | 3 |
| 2 | 4 | 1 | 3 |
| 2 | 4 | 5 | 3 |
| 2 | 5 | 1 | 3 |
| 2 | 5 | 4 | 3 |
now I wish to count the occurrence of item1 as well as item1 combined with item2 separately
I tried following:
with count_item1 AS (
select event_id, item_1_id, count(distinct set) AS c1 from table
group by event_id, item_1_id
), count_item1_and_item2 AS (
select event_id, item_1_id, item_2_id, count(distinct set) AS c2 from table
group by event_id, item_1_id, item_2_id
)
select t1.event_id, t1.item_1_id, t1.item_2_id, t1.c2, t2.c1
from count_item1_and_item2 AS t1
inner join count_item1 AS t2
on t1.event_id=t2.event_id and t1.item_1_id=t2.item_1_id
for example as table above
so the result for this should be:
| event id | item 1 id | item 2 id | c1 | c2 |
| 1 | 1 | 2 | 1 | 1 |
| 1 | 1 | 3 | 1 | 1 |
| 1 | 2 | 1 | 2 | 1 |
| 1 | 2 | 3 | 2 | 1 |
| 1 | 3 | 1 | 1 | 1 |
| 1 | 3 | 2 | 1 | 1 |
| 1 | 2 | 4 | 2 | 1 |
| 1 | 4 | 2 | 1 | 1 |
| 2 | 1 | 4 | 1 | 1 |
| 2 | 1 | 5 | 1 | 1 |
| 2 | 4 | 1 | 1 | 1 |
| 2 | 4 | 5 | 1 | 1 |
| 2 | 5 | 1 | 1 | 1 |
| 2 | 5 | 4 | 1 | 1 |
the meaning of each row is: in event_id, item 1 appeared c1 in distinct set and (item1, item2) appeared c2 in distinct set.
also count of (item1, item2) is equal to (item2, item1)
then I find a strange thing:
the occurrence of item1 itself should not less than the occurrence of item1 combined with item2, but I find that sometimes item1 combined with item2 has more count than count of item1, is there anything I did wrong here? I think my idea is right but I didn't get the result. I have being stacked in here for a weekend.
Related
I want to select picture file from photo_db where sid is the same as allotment_db so I wrote:
//allotment_db
+---------+---------+-----------+---------+
| id | rm_id | date | stts |
+---------+---------+-----------+---------+
| 1 | 1 |2019-10-01 | 1 |
| 2 | 2 |2019-10-01 | 1 |
| 3 | 3 |2019-10-01 | 1 |
| 4 | 1 |2019-10-02 | 1 |
| 5 | 2 |2019-10-02 | 1 |
+---------+---------+-----------+---------+
I want to select one row from photo_db ...
//photo_db
+---------+-----------+----------+-----------+
| id | rm_id | file | var |
+---------+-----------+----------+-----------+
| 1 | 1 | rm1.jpg | 0 |
| 2 | 1 | rm2.jpg | 0 |
| 3 | 1 | rm3.jpg | 9 |
| 4 | 2 | rm4.jpg | 0 |
| 5 | 2 | rm5.jpg | 9 |
| 6 | 2 | rm6.jpg | 0 |
| 7 | 3 | rm7.jpg | 0 |
| 8 | 3 | rm8.jpg | 0 |
| 9 | 3 | rm9.jpg | 9 |
| 10 | 1 | rm10.jpg | 0 |
+---------+-----------+----------+-----------+
Then, I wrote:
select *
from allotment_db alm
left
join photo_db pic
on pic.id = alm.id
where alm.date between '2019-10-01' and '2019-10-02'
and alm.stts = 1
and pic.var = 9
group
by alm.rm_id
And expect the result would come like this
//allotment_db
+---------+---------+-----------+---------+---------+
| id | rm_id | date | stts | file |
+---------+---------+-----------+---------+---------+
| 1 | 1 |2019-10-01 | 1 | rm3.jpg |
+---------+---------+-----------+---------+---------+
| 2 | 2 |2019-10-01 | 1 | rm5.jpg |
+---------+---------+-----------+---------+---------+
| 3 | 3 |2019-10-01 | 1 | rm9.jpg |
+---------+---------+-----------+---------+---------+
| 4 | 1 |2019-10-02 | 1 | rm3.jpg |
+---------+---------+-----------+---------+---------+
| 5 | 2 |2019-10-02 | 1 | rm5.jpg |
+---------+---------+-----------+---------+---------+
But the actual result return nothing even an error. Please correct me.
That is not how you should be using GROUP BY standard wise, also GROUP BY is not meant to "unduplicate" like that..
I assume you get a error when running your query?
SELECT list is not in GROUP BY clause and contains nonaggregated
column 'alm.id' which is not functionally dependent on columns in
GROUP BY clause; this is incompatible with
sql_mode=only_full_group_by"
From what it looks like you seams to be wanting these query resultsets to be merged as one resultset.
Query #1
SELECT
allotment_db.id
, allotment_db.rm_id
, allotment_db.date
, allotment_db.stts /* or (SELECT 1) AS stts -> 1 AS stts instead */
FROM
allotment_db
WHERE
allotment_db.date BETWEEN '2019-10-01' and '2019-10-02'
AND
stts = '1'
;
| id | rm_id | date | stts |
| --- | ----- | ---------- | ---- |
| 1 | 1 | 2019-10-01 | 1 |
| 2 | 2 | 2019-10-01 | 1 |
| 3 | 3 | 2019-10-01 | 1 |
| 4 | 1 | 2019-10-02 | 1 |
| 5 | 2 | 2019-10-02 | 1 |
Query #2
SELECT
photo_db.rm_id
, photo_db.file
FROM
photo_db
WHERE
photo_db.var = '9'
;
| rm_id | file |
| ----- | ------- |
| 1 | rm3.jpg |
| 2 | rm5.jpg |
| 3 | rm9.jpg |
So a option would be ..
Query
SELECT
allotment_db.id
, allotment_db.rm_id
, allotment_db.date
, allotment_db.stts /* or (SELECT 1) AS stts -> 1 AS stts instead */
, photo_db.rm_id
, photo_db.file
FROM (
SELECT
allotment_db.id
, allotment_db.rm_id
, allotment_db.date
, allotment_db.stts /* or (SELECT 1) AS stts -> 1 AS stts instead */
FROM
allotment_db
WHERE
allotment_db.date BETWEEN '2019-10-01' and '2019-10-02'
AND
stts = '1'
) AS allotment_db
INNER JOIN (
SELECT
photo_db.rm_id
, photo_db.file
FROM
photo_db
WHERE
photo_db.var = '9'
) AS photo_db
ON
allotment_db.rm_id = photo_db.rm_id
ORDER BY
id ASC
, allotment_db.rm_id ASC
Result
| id | rm_id | date | stts | rm_id | file |
| --- | ----- | ---------- | ---- | ----- | ------- |
| 1 | 1 | 2019-10-01 | 1 | 1 | rm3.jpg |
| 2 | 2 | 2019-10-01 | 1 | 2 | rm5.jpg |
| 3 | 3 | 2019-10-01 | 1 | 3 | rm9.jpg |
| 4 | 1 | 2019-10-02 | 1 | 1 | rm3.jpg |
| 5 | 2 | 2019-10-02 | 1 | 2 | rm5.jpg |
see demo
I have 4 tables:
comments
+----+-----------+--------------+-------+
| id | content | user_id | article_id |
+----+-----------+--------------+-------+
| 1 | Comment 1 | 2 | 5 |
| 2 | Comment 2 | 5 | 3 |
| 3 | Comment 3 | 1 | 6 |
| 4 | Comment 4 | 6 | 8 |
| 5 | Comment 5 | 1 | 6 |
| ...| ... | ... | ... |
+----------------+---------+------------+
votes
+----+----------+--------------+---+
| id | type | user_id | article_id |
+----+----------+--------------+---+
| 1 | 1 | 2 | 5 |
| 2 | 1 | 3 | 3 |
| 3 | 0 | 1 | 6 |
| 4 | 1 | 7 | 4 |
| 5 | 0 | 9 | 4 |
| 6 | 0 | 1 | 6 |
| ...| ... | ... | ... |
+------------+----------+----------+
notifications (object_id is the id of the vote|comment)
+----+----------+--------------+-------------+-------------+--------------+
| id | object_url| object_id |activitytype_id| sender_id | recipient_id |
+----+----------+------------+---------------+-------------+--------------+
| 1 | /../../.. | 1 | 2 | 2 | 6 |
| 2 | /../../.. | 2 | 2 | 3 | 2 |
| 3 | /../../.. | 1 | 1 | 2 | 7 |
| 3 | /../../.. | 2 | 1 | 5 | 2 |
| 3 | /../../.. | 3 | 1 | 1 | 3 |
| 3 | /../../.. | 3 | 3 | 1 | 2 |
| 3 | /../../.. | 4 | 2 | 7 | 8 |
| 3 | /../../.. | 5 | 3 | 9 | 1 |
| 3 | /../../.. | 6 | 3 | 1 | 5 |
| ...| ... | ... | ... | | |
+----+-----------+-----------+---------------+-------------+--------------+
activitytypes
+----+------------+
| id | label |
+----+------------+
| 1 | comment |
| 2 | vote up |
| 3 | vote down |
| ...| ... |
+-----------------+
I would like to get notifications like on stackoverflow.
I want to query the last notification (with comment content if the activity type is a comment or null if not) for every activitytype and object_url combinaison for a specific user.
For example I have 3 artiles A,B and C which all have 3 comments, 4 voteup and 2 votedown. How to get the last comment, voteup and votedown for every article ?
I have tried this query:
SELECT n.id, n.object_url , n.object_id, n.activitytype_id, IF(n.activitytypeId = 1,
(SELECT content FROM comments WHERE id=n.object_id), null) AS activitycontent
FROM notifications n WHERE n.recipient_id =1
GROUP BY n.activitytype_id,n.object_url
ORDER BY n.id DESC
But it doesn't work. Can anyone help ?
EDIT:
This following query in farhadamjady's answer gives me the first comment:
SELECT
n.id,
n.object_url,
n.object_id,
n.activitytype_id,
cm.content AS activitycontent
FROM
notifications n
LEFT OUTER JOIN `COMMENT` AS cm ON cm.id = n.object_id and n.activitytypeId = 1
WHERE
n.recipient_id = 1
GROUP BY
n.activitytype_id,
n.object_url
HAVING MAX(cm.id)
ORDER BY
n.id DESC
How can I change it to get the last ?
you should use left outer join like this :
SELECT
n.id,
n.object_url,
n.object_id,
n.activitytype_id,
cm.content AS activitycontent
FROM
notifications n
LEFT OUTER JOIN `COMMENT` AS cm ON cm.id = n.object_id and n.activitytypeId = 1
WHERE
n.recipient_id = 1
GROUP BY
n.activitytype_id,
n.object_url
HAVING MAX(cm.id)
ORDER BY
n.id DESC
My first data table is couponsnmaster
+-----------+----------+------------+
|couponsnid | couponid | couponsn |
+-----------+----------+------------+
| 1 | 1 | 1000 |
| 2 | 1 | 1001 |
| 3 | 1 | 1002 |
| 4 | 1 | 1003 |
| 5 | 1 | 1004 |
| 6 | 1 | 1005 |
+-----------+----------+------------+
My second data table is distribute
+-----------+--------------+--------------+--------------+
| distid | couponid | couponsnid | status |
+-----------+--------------+--------------+--------------+
| 1 | 1 | 1 | distribute |
| 2 | 1 | 2 | distribute |
| 3 | 1 | 3 | distribute |
| 4 | 1 | 1 | returned |
+-----------+--------------+--------------+--------------+
I want to fetch all "couponsn" from "couponsnmaster" with respect to "couponid" except status is " distribute" or "sold" or "bonus" in table "distribute"....
Try this query:
SELECT c.couponsn FROM
couponsmaster c INNER JOIN distribute d
ON c.couponsid = d.couponsid
WHERE d.status NOT IN('distribute','sold','bonus')
i want select tree from
id | parent_id | path | order
---------------------------------------
1 | 0 | /1/ | 1
2 | 1 | /1/2/ | 1
3 | 2 | /1/2/3/ | 1
4 | 1 | /1/4/ | 2
5 | 4 | /1/4/5/ | 2
6 | 4 | /1/4/6/ | 1
like this
| 1 | | |
| | 2 | |
| | | 3 |
| | 4 | |
| | | 6 |
| | | 5 |
in one query.
Something like
select * from tbl ORDER BY COALESCE(length(path),0), order asc
but this select sorted groups of each tree level
1
-2
-4
--3
--6
--5
thanks
I now find my original table structure was not good, so want to change it.
But I am having a hard time designing queries to obtain totals in rows with the new structure.
current structure:
+----------+-------+-------+-------+-------+
| state | shop | item0 | item1 | item2 |
+----------+-------+-------+-------+-------+
| 5 | 0 | 1 | 2 | 3 |
| 5 | 1 | 1 | 2 | 3 |
| 5 | 2 | 1 | 2 | 3 |
| 4 | 3 | 1 | 2 | 3 |
+----------+-------+-------+-------+-------+
(quantities of items at shop)
I want to change to these 2 tables:
shops table
+---------+--------+
| shop_id | state |
+---------+--------+
| 0 | 5 |
| 1 | 5 |
| 2 | 5 |
| 3 | 4 |
+---------+--------+
items table
+------------+--------------+
| shop | item | quantity |
+------------+--------------+
| 0 | 0 | 1 |
| 0 | 1 | 2 |
| 0 | 2 | 3 |
| 1 | 0 | 1 |
| 1 | 1 | 2 |
| 1 | 2 | 3 |
| 2 | 0 | 1 |
| 2 | 1 | 2 |
| 2 | 2 | 3 |
| 3 | 0 | 1 |
| 3 | 1 | 2 |
| 3 | 2 | 3 |
+------------+--------------+
The old layout allowed simple queries for getting totals by row:
SELECT state,SUM(item0) t0,SUM(item1) t1,SUM(item2) t2
FROM shops
WHERE state=5
+--------+---------+---------+----------+
| state | t0 | t1 | t2 |
+--------+---------+---------+----------+
| 5 | 3 | 6 | 9 |
+--------+---------+---------+----------+
With the new structure,
I can get the totals in column as follows:
SELECT item,SUM(quantity) total
FROM shops
LEFT JOIN items ON shop=shopid
WHERE state=5
GROUP by item
+--------+---------+
| item | total |
+--------+---------+
| 0 | 3 |
+--------+---------+
| 1 | 6 |
+--------+---------+
| 2 | 9 |
+--------+---------+
but how do I get the totals in rows:
+--------+---------+---------+----------+
| state | t0 | t1 | t2 |
+--------+---------+---------+----------+
| 4 | 1 | 2 | 3 |
| 5 | 3 | 6 | 9 |
+--------+---------+---------+----------+
You might try using a few more JOINs:
SELECT S.state,
SUM(T0.quantity) AS "T0",
SUM(T1.quantity) AS "T1",
SUM(T2.quantity) AS "T2"
FROM shops AS S
LEFT JOIN items AS T0 ON S.shop_id = T0.shop_id AND T0.item=0
LEFT JOIN items AS T1 ON S.shop_id = T1.shop_id AND T1.item=1
LEFT JOIN items AS T2 ON S.shop_id = T2.shop_id AND T2.item=2
GROUP BY S.state
There might be an easier way.