Limiting MySQL results based on a field - mysql

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

Related

SQL Distinct a column with conditions

I'm working on a query where I need to count distinct CarId row when the column LocationId is not null and get all CarId if its null or 0 but the query that I tried distincts all the CarId even if its null
#LocId int
Select Count(distinct a.CarId) from VehicleDetails a
inner join VehicleDocuments b on a.DocId=b.DocId
left join VehicleShipmentDetails dpg on dpg.VehicleShipmentId= b.VehicleShipmentId
where b.LogicalDelete=0 and a.LogicalDelete=0
and (dpg.LocationId= #LocId or dpg.LocationId= 0 or dpg.LocationId is null)
| ID | CarId | LocationId | DateCreated |
|------+----------------+-----------------+---------------|
| 1 | 1 | 5 | 02/03/2019 |
| 2 | 2 | null | 01/14/2019 |
| 3 | 2 | 0 | 02/03/2019 |
| 4 | 2 | 5 | 12/30/2018 |
| 5 | 4 | 3 | 01/10/2019 |
| 6 | 3 | 5 | 02/14/2019 |
| 7 | 2 | 5 | 03/13/2019 |
Desired output:
| ID | CarId | LocationId | DateCreated |
+------+----------------+-----------------+---------------+
| 1 | 1 | 5 | 02/03/2019 |
| 2 | 2 | null | 01/14/2019 |
| 3 | 2 | 0 | 02/03/2019 |
| 4 | 2 | 5 | 03/13/2019 |
| 5 | 4 | 3 | 01/10/2019 |
| 6 | 3 | 5 | 02/14/2019 |
Current Output
| ID | CarId | LocationId | DateCreated |
+------+----------------+-----------------+---------------+
| 1 | 1 | 5 | 02/03/2019 |
| 2 | 2 | 5 | 01/14/2019 |
| 3 | 4 | 3 | 01/10/2019 |
| 4 | 3 | 5 | 02/14/2019 |
Im getting a count of 4 but i needed to have 6 as the Count
EDIT: My goal is to remove the row to Distinct CarId if the value of the LocationId is Null or 0 but on my Current code, It distincts all CarId that is null,0 and equals to #LocId
You can query something like this, replace your_table by your actual set of data.
SELECT ID, CardId, LocationId, DateCreated
FROM your_table as T
WHERE NOT EXISTS (SELECT *
FROM your_table as T1
WHERE T.ID > T1.ID AND T.CarID = T1.CarID)
In SQL, you can use the statement CASE to manage conditions (just like the "if then else" in other programming languages). In your case this function could help because you have two differents cases to handle.

Get standings/ranking based on win percentage from match-ups table

I have a table of Players and table of MatchUps. The MatchUps table has a winner_id column and a loser_id column. Can I get a standings/ranking based on winning percentage in one query? It would be great if I could return something like this for each player.
PlayerName - winCount - lossCount - winPercentage
I'm a SQL lightweight so things I've tried haven't come close. I've basically just been able to get a wins count for each player and that's it.
Here's an example players table:
+----+-------------------------------------+
| id | name |
+----+-------------------------------------+
| 1 | Iron Man |
| 2 | Gaurdians Of The Galaxy |
| 3 | Batman Begins |
| 4 | X-Men |
| 5 | Captain America: The First Avenger |
| 6 | Superman II |
| 7 | Captain America: The Winter Soldier |
| 8 | X2: X-Men United |
| 9 | X-Men: First Class |
| 10 | Superman: The Movie |
| 11 | Batman |
| 12 | The Avengers |
| 13 | The Incredibles |
| 14 | The Dark Knight |
+----+-------------------------------------+
Here's a sample match-ups table:
+----+-----------+----------+
| id | winner_id | loser_id |
+----+-----------+----------+
| 1 | 5 | 6 |
| 2 | 2 | 9 |
| 3 | 1 | 5 |
| 4 | 1 | 6 |
| 5 | 4 | 13 |
| 6 | 1 | 13 |
| 7 | 1 | 2 |
| 8 | 1 | 9 |
| 9 | 3 | 8 |
| 10 | 2 | 8 |
| 11 | 1 | 8 |
| 12 | 1 | 12 |
| 13 | 2 | 10 |
| 14 | 1 | 10 |
| 15 | 2 | 4 |
| 16 | 1 | 4 |
| 17 | 2 | 13 |
| 18 | 3 | 11 |
| 19 | 2 | 3 |
| 20 | 1 | 3 |
+----+-----------+----------+
This is one way to do this:
Fiddle:
http://sqlfiddle.com/#!9/731d6/1/0
select p.name as playername,
x.wincount,
x.losscount,
case when x.wincount = 0 then 0
else x.wincount / x.total_games
end as winpercentage
from ( select player_id,
sum(case when outcome = 'W' then 1 else 0 end) as wincount,
sum(case when outcome = 'L' then 1 else 0 end) as losscount,
count(*) as total_games
from (
select winner_id as player_id,
'W' as outcome
from matchups
union all
select loser_id,
'L'
from matchups
) x
group by player_id
) x
join players p
on x.player_id = p.id
Please try this :
select id,name,
ifnull(t1.win_count,0) as win_count,
ifnull(t2.loss_count,0) as loss_count,
concat(round((ifnull(t1.win_count,0) / (ifnull(t2.loss_count,0)+ifnull(t1.win_count,0))) * 100,0),' %') as win_percentage
from player as tbl
left join (
select winner_id,count(*) as win_count from matchups group by winner_id
) as t1 on t1.winner_id = tbl.player_id
left join (
select loser_id,count(*) as loss_count from matchups group by loser_id
) as t2 on t2.loser_id = tbl.player_id

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

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

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..

Create a view with top N per group rows in mysql

I need to create a view that stores the top 200 rows for each userId from another table that has userId as one of its columns.
Found a way to do this using user-defined variables in SELECT, but then MySQL does not allow views with variables in the SELECT.
This is a part of the SELECT statement to be used in the view:
select *,#num:= if(#userId = userId, #num + 1, 1) as row_number,
#userId := userId as dummy from (SELECT #userId:=0, #num:=0) as init
Is it possible to replace #userId and #num with functions instead? Similar examples would of great help!!
Consider the following...
SELECT * FROM results;
+----+------------+--------+-------+-------+
| id | discipline | member | event | value |
+----+------------+--------+-------+-------+
| 1 | 1 | 2 | 4 | 10 |
| 2 | 1 | 1 | 4 | 8 |
| 3 | 1 | 2 | 5 | 9 |
| 4 | 2 | 3 | 5 | 9 |
| 5 | 1 | 2 | 6 | 11 |
| 6 | 1 | 2 | 7 | 11 |
| 7 | 1 | 2 | 1 | 11 |
| 8 | 1 | 2 | 3 | 7 |
| 9 | 1 | 1 | 8 | 8 |
+----+------------+--------+-------+-------+
Say I want to get the top 3 'value' results for each member. In the event of a tie, I'll take the lower 'event' first...
SELECT x.*
, COUNT(*) rank
FROM results x
JOIN results y
ON y.member = x.member
AND (y.value > x.value OR (y.value = x.value AND y.event <= x.event))
GROUP
BY x.member
, x.value
, x.event
HAVING COUNT(*) <=3;
+----+------------+--------+-------+-------+---------+
| id | discipline | member | event | value | rank |
+----+------------+--------+-------+-------+---------+
| 2 | 1 | 1 | 4 | 8 | 1 |
| 9 | 1 | 1 | 8 | 8 | 2 |
| 7 | 1 | 2 | 1 | 11 | 1 |
| 5 | 1 | 2 | 6 | 11 | 2 |
| 6 | 1 | 2 | 7 | 11 | 3 |
| 4 | 2 | 3 | 5 | 9 | 1 |
+----+------------+--------+-------+-------+---------+