Select from two table with "and" condition and MIN() function - mysql

I have the table :
*ruletbl
| id_rule | code_rule |
-----------------------
| 1 | R01 |
| 2 | R01 |
| 3 | R01 |
| 4 | R02 |
| 5 | R02 |
| 6 | R02 |
-----------------------
and second table *detailRuletbl:
| id_detailRule | id_rule | id_sym | codeDetailrule | orderNO |
---------------------------------------------------------------------
| 1 | 1 | 1 | R01#1 | 1 |
| 2 | 1 | 2 | R01#1 | 1 |
| 3 | 1 | 3 | R01#1 | 1 |
| 4 | 2 | 4 | R01#2 | 2 |
| 5 | 2 | 1 | R01#2 | 2 |
| 6 | 2 | 2 | R01#2 | 2 |
| 7 | 3 | 4 | R01#3 | 3 |
| 8 | 3 | 3 | R01#3 | 3 |
| 9 | 3 | 1 | R01#3 | 3 |
| 10 | 4 | 6 | R02#1 | 1 |
| 11 | 4 | 7 | R02#1 | 1 |
| 12 | 4 | 5 | R02#1 | 1 |
| 13 | 5 | 4 | R02#2 | 2 |
| 14 | 5 | 1 | R02#2 | 2 |
| 15 | 5 | 2 | R02#2 | 2 |
| 16 | 5 | 8 | R02#2 | 2 |
| 17 | 6 | 6 | R02#3 | 3 |
| 18 | 6 | 8 | R02#3 | 3 |
| 19 | 6 | 2 | R02#3 | 3 |
| 20 | 6 | 1 | R02#3 | 3 |
--------------------------------------------------------------------
I want to select from those table with "and" condtiion in input one array (1,2) and MIN(orderNo) if "codeDetailrule is same like "R01#1 and R01#2" so first elimination with "and" condtion likes this code:
SELECT codeDetailrule, orderNo
FROM detailRuletbl
WHERE id_sym
IN ( 1,2 )
GROUP BY codeDetailrule
HAVING COUNT( * ) =2
the result :
| codeDetailRule | orderNo |
----------------------------
| R01#1 | 1 |
| R01#2 | 2 |
| R02#2 | 2 |
| R02#3 | 3 |
----------------------------
and if we use MIN(orderNO) the result should be :
| codeDetailRule | orderNo |
----------------------------
| R01#1 | 1 |----------------------> this is my expect result
| R02#2 | 2 |
----------------------------
Can anyone can help me?
Till now this is my trial :
SELECT codeDetailrule, orderNo
FROM detailRuletbl
WHERE id_sym
IN ( 1,2 )
GROUP BY codeDetailrule
HAVING COUNT( * ) =2
AND orderNo= ( SELECT MIN( X.orderNo) FROM detailRuletbl,
(SELECT codeDetailrule, orderNoFROM detailRuletbl
WHERE id_sym IN ( 1, 2 ) GROUP BY codeDetailrule
HAVING COUNT( * ) =2
)
AS X
)
and result :
| codeDetailrule | orderNo |
-------------------------------
| R01#1 | 1 |
-------------------------------
Anyone have any Idea? Please help.

SELECT codeDetailrule, orderNo
FROM detailRuletbl
WHERE id_sym
IN ( 1,2 ) AND orderNo IN (
SELECT MIN(orderNo) FROM detailRuletbl
GROUP BY orderNo
HAVING COUNT(*) = 2
)
I'm sorry if I misunderstood what you wanted

I have got the rigth answer for MIN() function and check "and" condtion
SELECT a.codeRule, a.id_rule, MIN( a.orderNo)
FROM (ruletbl AS b, detailRuletbl AS a)
INNER JOIN (
SELECT h.codeDetailrule, h.id_rule AS irule, i.codeRule AS
krule, MIN( h.oderNo) AS norderno
FROM detailruletbl AS h, ruletbl AS i
WHERE h.id_rule = i.id_rule
AND h.id_sym
IN ( 1,2 )
GROUP BY h.codeDetailrule
HAVING COUNT( * ) =2
)sMin ON a.id_rule= sMin.irule
GROUP BY sMin.krule

Related

How to select row according to row in range of table 1 date with mysql?

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

Mysql Best way to query notifications like on stackoverflow

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

MySQL : Select three last item INNER JOIN [duplicate]

This question already has answers here:
Using LIMIT within GROUP BY to get N results per group?
(14 answers)
Closed 7 years ago.
Just have a tricky blockING with MySQL.
I've 3 tables :
TV
| TV_ID | TV_name |
----------------------
| 1 | HBO |
| 2 | BBC |
| 3 | Fox news |
----------------------
----------------------
----------------------
Emission
| E_ID | E_TV_ID | E_NAME |
-------------------------------
| 1 | 1 | Weather |
| 2 | 1 | News |
| 3 | 1 | FAKE1 |
| 4 | 1 | FAKE2 |
| 5 | 1 | FAKE3 |
| 6 | 1 | FAKE4 |
| 7 | 2 | FAKE5 |
| 8 | 2 | FAKE6 |
| 9 | 2 | FAKE7 |
| 10 | 2 | FAKE8 |
| 11 | 2 | FAKE9 |
| 12 | 2 | FAKE10 |
| 13 | 2 | FAKE11 |
| 14 | 3 | FAKE12 |
| 15 | 3 | FAKE13 |
| 16 | 3 | FAKE14 |
| 17 | 3 | FAKE15 |
| 18 | 3 | FAKE16 |
| 19 | 3 | FAKE17 |
| 20 | 3 | FAKE18 |
-------------------------------
-------------------------------
-------------------------------
Replay
| R_ID | R_E_ID | R_DATE | R_URL_REPLAY |
-------------------------------------------
| 1 | 1 | 20150431 | URL1 |
| 2 | 20 | 20150431 | URL2 |
| 3 | 19 | 20150431 | URL3 |
| 4 | 2 | 20150431 | URL4 |
| 5 | 7 | 20150431 | URL5 |
| 6 | 16 | 20150430 | URL6 |
| 7 | 10 | 20150430 | URL7 |
| 8 | 1 | 20150430 | URL8 |
| 9 | 4 | 20150430 | URL9 |
| 10 | 9 | 20150430 | URL10 |
| 11 | 19 | 20150429 | URL11 |
| 12 | 2 | 20150429 | URL12 |
| 13 | 1 | 20150429 | URL13 |
| 14 | 12 | 20150429 | URL14 |
-------------------------------------------
-------------------------------------------
-------------------------------------------
And I want to create ONLY ONE query to get 3rd last emission of each TV, order by date and TV (if possible).
So for this exemple, I've 3 TV. 3*3 = 9 emissions, like :
| TV_ID | E_NAME | R_URL_REPLAY |
-------------------------------------
| 1 | Weather | URL1 |
| 1 | FAKE2 | URL4 |
| 1 | FAKE6 | URL8 |
| 2 | FAKE3 | URL5 |
| 2 | FAKE8 | URL7 |
| 2 | FAKE7 | URL10 |
| 3 | FAKE18 | URL2 |
| 3 | FAKE17 | URL3 |
| 3 | FAKE14 | URL6 |
I've try many solution (INNER JOIN -- SELECT .. FROM ( SELECT ...) -- Use var #:= -- Sub-sub-sub-sub query ) but not works..
Only works if I use UNION, but I've more than 20 TV, and write 20 UNION is really urgly..
If you have suggestion,
Thanks in advance,
It's not straightforward, but in a nutshell, sort your replays by tv and date, then rank them, then select those that match your rank criteria.
select *
from (
select if(#prev = e_tv_id, #rank := #rank +1, #rank := 1 and #prev := e_tv_id) as rank, q.*
from (
select e.e_tv_id, r_date, r_url_replay
from emission e
join (select #prev := 0, #rank := 1) q
inner join replay r
on r.r_e_id = e.e_id
order by e.e_tv_id asc, r.r_date desc
) q
) qq
where rank <=3 ;
demo here

select sum of product price for every 1 id productcategory

i want to find solution for my query problem. I need to find the SUM of all priceProduct*quantity and separated with each of productcategory. I have already made a query, but it takes longer time to executed it. this is my query,
SELECT
pb.ProductCategoryID,
pb.ProductCategoryDescription,
(SELECT
SUM((SELECT pd.HPP FROM `price details` pd WHERE pd.ProductID = pdt.ProductID ORDER BY pd.PriceDetailID DESC LIMIT 1)*
(SELECT StockProductBallance FROM `stock product` sp WHERE sp.ProductID = pdt.ProductID ORDER BY sp.StockProductID DESC LIMIT 1))
FROM product pdt
WHERE pdt.ProductCategoryID = pb.ProductCategoryID
) AS Total
FROM `product category` pb
GROUP BY pb.ProductCategoryID
this my example table
table product:
+------+-------+
| id_p | id_pc |
+------+-------+
| 1 | 3 |
| 2 | 4 |
| 3 | 3 |
| 4 | 4 |
+------+-------+
table productcategory:
+-------+---------+
| id_pc | pc_name |
+-------+---------+
| 3 | new_pc |
| 4 | old_pc |
+-------+---------+
table price details:
+---------------+------+-----+
| PriceDetailID | id_p | hpp |
+---------------+------+-----+
| 1 | 1 | 100 |
| 2 | 1 | 110 |
| 3 | 1 | 120 |
| 4 | 2 | 200 |
| 5 | 2 | 210 |
| 6 | 2 | 220 |
+---------------+------+-----+
table stockProduct:
+-----------------+------+---------------+
| id_stockProduct | id_p | stockballance |
+-----------------+------+---------------+
| 1 | 1 | 10 |
| 2 | 1 | 11 |
| 3 | 1 | 12 |
| 4 | 2 | 20 |
| 5 | 2 | 21 |
| 6 | 2 | 22 |
+-----------------+------+---------------+
Really need your help guys, for better query..

Limiting MySQL results based on a field

I've table called Products in that type is field type value might be any one of these values 1,2,3,4.
Now I'would like to get the result as
1. Group the results based on 'type'
2. And Limit the results for each group to 5.
How can I achieve this, Currently I'm using following query
SELECT
*,
(
(
CASE
WHEN product_title LIKE '%xyz%'
THEN 2
ELSE 0
END
) + (
CASE
WHEN product_description LIKE '%xyz%'
THEN 1
ELSE 0
END
)
) AS relevance
FROM
Products
WHERE (
(
product_title LIKE '%xyz%'
OR product_description LIKE '%xyz%'
)
)
AND product_available = 1
AND product_deleted <> 1
ORDER BY relevance DESC
SELECT * FROM products;
+------------+------+
| product_id | type |
+------------+------+
| 1 | 4 |
| 2 | 3 |
| 3 | 2 |
| 4 | 4 |
| 5 | 3 |
| 6 | 1 |
| 7 | 4 |
| 8 | 3 |
| 9 | 4 |
| 10 | 2 |
| 11 | 2 |
| 12 | 1 |
| 13 | 3 |
| 14 | 2 |
| 15 | 3 |
| 16 | 1 |
| 17 | 2 |
| 18 | 1 |
| 19 | 2 |
| 20 | 4 |
| 21 | 2 |
+------------+------+
SELECT x.*
FROM products x
JOIN products y
ON y.type = x.type
AND y.product_id <= x.product_id
GROUP
BY x.product_id
HAVING COUNT(*) <=3
ORDER
BY type
, product_id;
+------------+------+
| product_id | type |
+------------+------+
| 6 | 1 |
| 12 | 1 |
| 16 | 1 |
| 3 | 2 |
| 10 | 2 |
| 11 | 2 |
| 2 | 3 |
| 5 | 3 |
| 8 | 3 |
| 1 | 4 |
| 4 | 4 |
| 7 | 4 |
+------------+------+
Here's a simple one
SELECT
p.id,
p.type
FROM
Products p
WHERE
5 > (SELECT COUNT(id) from Products where id < p.id and type = p.type)
I have created the sqlfiddle for it, http://sqlfiddle.com/#!2/ab0c00/15