Don't return the lowest value if - mysql

The goal
Don't return the lowest price whose its markets are suspended.
The problem
I don't know the syntax.
The scenario
There is the following stored procedure to get the lowest and the biggest price of a specific product:
BEGIN
Select Min(Case When product.PromotionalPrice = 0
Then product.OriginalPrice Else
Least(product.PromotionalPrice, product.OriginalPrice)
End) As minProductPrice,
Max(Case When product.PromotionalPrice = 0
Then product.OriginalPrice Else
Least(product.PromotionalPrice, product.OriginalPrice)
End) As maxProductPrice
From products As product
Where product.Name = 'Playstation 3';
END
The context is: there are markets and products. Products belong to markets. If some market is suspended, then doesn't display its products and nor add them to max/min price comparison.
Can you all understand? I want to exclude the products whose its markets are suspended from the Min or Max statement of above's query.
The tables
Here is the markets table:
+----+------+-------------+
| Id | Name | SituationId |
+----+------+-------------+
| 1 | A | 1 |
+----+------+-------------+
| 2 | B | 2 |
+----+------+-------------+
| 3 | C | 3 |
+----+------+-------------+
Here is the markets_situations table:
+----+-----------+
| Id | Name |
+----+-----------+
| 1 | Neutral |
+----+-----------+
| 2 | Premium |
+----+-----------+
| 3 | Suspended |
+----+-----------+
And finally, here is the products table:
+----+---------------+--------+------------------+---------------+
| Id | Name | Market | PromotionalPrice | OriginalPrice |
+----+---------------+--------+------------------+---------------+
| 1 | Xbox 360 | 1 | 0 | 225,00 |
+----+---------------+--------+------------------+---------------+
| 2 | Xbox 360 | 2 | 99,00 | 175,00 |
+----+---------------+--------+------------------+---------------+
| 3 | Xbox 360 | 3 | 0 | 135,00 |
+----+---------------+--------+------------------+---------------+
| 4 | Playstation 3 | 1 | 0 | 189,00 |
+----+---------------+--------+------------------+---------------+
| 5 | Playstation 3 | 2 | 125,00 | 165,00 |
+----+---------------+--------+------------------+---------------+
| 6 | Playstation 3 | 3 | 110,00 | 185,00 |
+----+---------------+--------+------------------+---------------+
To enhance the comprehension
I don't want to display 110,00 as the Min price of the stored procedure's result because its market (C) is Suspended.
What I already did
I already tried the following, but without success:
BEGIN
[...]
Where product.Name = 'Playstation 3'
And marketSituation.Id <> 3;
END
What happens? The And condition does nothing. The query keeps returning me the price of the suspended market.

Select Min(Case When product.PromotionalPrice = 0
Then product.OriginalPrice Else
Least(product.PromotionalPrice, product.OriginalPrice)
End) As minProductPrice,
Max(Case When product.PromotionalPrice = 0
Then product.OriginalPrice Else
Least(product.PromotionalPrice, product.OriginalPrice)
End) As maxProductPrice
From products As product
Inner join markets on product.market = markets.id AND markets.SituationId <> 3
Where product.Name = 'Playstation 3';

How about something like
Select Min(Case When product.PromotionalPrice = 0
Then product.OriginalPrice Else
Least(product.PromotionalPrice, product.OriginalPrice)
End) As minProductPrice,
Max(Case When product.PromotionalPrice = 0
Then product.OriginalPrice Else
Least(product.PromotionalPrice, product.OriginalPrice)
End) As maxProductPrice
From products As product INNER JOIN
Markets ON Product.Market = Markets.Id
Where product.Name = 'Playstation 3'
AND Markets.SituationID <> 3

Related

One row result with multiple join in MySQL

I have 3 tables like the following.
Table "mansioni":
id_mansione | desc_mansione
1 | production
2 | office
3 | transport
Table "dipendente": store id, name and surname:
id_dip | nome_dip | cognome_dip
1 | piero | rossi
2 | marco | rossi
Table dipendenti_iddip: store the association between "dipendente" and table "mansioni"
iddip_mansione | num_mansione | id_mansione
1 | 1 | 1
1 | 2 | 2
2 | 1 | 2
2 | 2 | 3
Now I need a query that give me a result like this:
id_dip | nome_dip | cognome_dip | mansione1 | mansione2 | mansione3
1 | piero | rossi | production| office |
2 | marco | rossi | office | transport |
I arrived to the following query but with this I can only see the "id_mansione" and not the "desc mansione" field
select i.id_dip,
i.nome_dip,
i.cognome_dip,
max(case when t.num_mansione='1' then t.id_mansione end) Mansione1,
max(case when t.num_mansione='2' then t.id_mansione end) Mansione2,
max(case when t.num_mansione='3' then t.id_mansione end) Mansione3
from dipendente i
left join dipendenti_iddip t
on i.id_dip = t.iddip_mansione
group by i.id_dip, i.nome_dip, i.cognome_dip
How can I arrive to my result?
Thanks...
Add join on mansioni and replace t.id_mansione with m.desc_mansione
select i.id_dip,
i.nome_dip,
i.cognome_dip,
max(case when t.num_mansione = '1' then m.desc_mansione end) Mansione1,
max(case when t.num_mansione = '2' then m.desc_mansione end) Mansione2,
max(case when t.num_mansione = '3' then m.desc_mansione end) Mansione3
from dipendente i
join dipendenti_iddip t
on i.id_dip = t.iddip_mansione
join mansioni m on m.id_mansione = t.id_mansione
group by i.id_dip

case when condition with group by query with mysql

Below is my mysql query :
SELECT u.id,
CASE WHEN (p.PaymentType = "FreeCredit") THEN SUM(p.CreditedAmount) ELSE 0 END AS freecredit ,
CASE WHEN (p.PaymentType = "Online") THEN SUM(p.CreditedAmount) ELSE 0 END AS onlinepayment,
CASE WHEN (p.PaymentType = "Cash") THEN SUM(p.CreditedAmount) ELSE 0 END AS Cash
FROM users as u
LEFT JOIN payment as p on u.id = p.UserId AND p.PaymentSucc = "Yes"
WHERE
`u`.`UserType` = 'User'
GROUP BY p.UserId
ORDER BY u.id DESC;
Required result : in payment table I have 3 payment type in result I required to show sum for particular payment type for single user like below,
userid= 1974
PaymentType = FreeCredit,CreditedAmount= 120
PaymentType = Online ,CreditedAmount== 140
PaymentType = cash ,CreditedAmount==100
PaymentType = FreeCredit,CreditedAmount== 100
PaymentType = Online ,CreditedAmount== 120
PaymentType = cash ,CreditedAmount==170
in required result it should be as below,
id freecredit onlinepayment Cash
1972 220 260 270
from my query ,I am not able to get above result ,please can any person help me to resolve my this mysql query issue:
I will appreciate best answer.
This is a good question (y)
So,
Here's table user:
mysql> select * from user;
+----+-----------+
| id | user_type |
+----+-----------+
| 1 | krish |
| 2 | bala |
+----+-----------+
Here's table payment:
mysql> select * from payment;
+------+-------------+----------------+
| id | PaymentType | CreditedAmount |
+------+-------------+----------------+
| 1 | FreeCredit | 120 |
| 1 | Online | 140 |
| 1 | cash | 100 |
| 1 | FreeCredit | 100 |
| 1 | Online | 120 |
| 1 | cash | 170 |
| 2 | FreeCredit | 500 |
| 2 | Online | 450 |
| 2 | FreeCredit | 230 |
+------+-------------+----------------+
The goal is to have - for each ID - the sum of 'FreeCredit' / 'Online' / 'cash'
select u.id, sum(case when PaymentType = "FreeCredit" then
CreditedAmount else 0 end) as freeamnt, sum(case when PaymentType =
'Online' then CreditedAmount else 0 end) as Online, sum(case when
PaymentType = 'cash' then Creditedamount else 0 end) as cash from user
as u left join payment as p on u.id=p.id group by p.id order by u.id
desc;
+----+----------+--------+------+
| id | freeamnt | Online | cash |
+----+----------+--------+------+
| 3 | 0 | 0 | 0 |
| 2 | 730 | 450 | 0 |
| 1 | 220 | 260 | 270 |
+----+----------+--------+------+
3 rows in set (0.03 sec)
Note:
I simulated a sample based upon your examples
The query is based on my sample and it won't have all the 'where' conditions you have given

Select sum of column according to case statement in mysql query

I have a table with three columns:
1. store name
2. data type (sales, return)
3. qty
---------------------------
| Stores | Data | Qty |
---------------------------
| HM | Sales | 15 |
| RD | Sales | 10 |
| HM | Return | 4 |
| RD | Return | 2 |
I want to select all store names, sales qty, return qty as following
--------------------------
| Store | Sales | Return |
--------------------------
| HM | 15 | 4 |
| RD | 10 | 2 |
Here's what I've tried:
SELECT store,
CASE `data`
WHEN 'Sales' THEN SUM(qty)
ELSE NULL
END as `Sales`,
CASE `data`
WHEN 'Return' THEN SUM(qty)
ELSE NULL
END as `Return`
FROM `full_report`
GROUP BY store
Result: I get wrong sales qty and Null for return qty!
You can use conditional aggregation . . . mixing case with sum():
select fr.store,
SUM(case when fr.data = 'Sales' then fr.qty else 0 end) as Sales,
SUM(case when fr.data = 'Return' then fr.qty else 0 end) as Returns
from full_report fr
group by fr.store;

SQL - Query multiple rooms with different Adults/Children per hotel

I have a simple query where I select available x Rooms with x Adults + x Children per hotel that matches a date range, but I'm having a hard time trying to figure out how to query a list of rooms per hotel like this:
1 Room with 2 Adults / 0 Children
1 Room with 4 Adults / 2 Children
1 Room with 2 Adults / 1 Children
Here is my query:
SELECT COUNT(pl.day) AS Days,
p.property_ID AS Hotel_ID,
p.name AS Hotel_Name,
r.room_name AS Room_Name,
r.room_type_ID AS Room_ID
FROM property p
INNER JOIN room_type r ON p.property_ID=r.property_ID
AND (r.max_adults >= 3
AND r.max_children >= 0)
INNER JOIN plan pl ON pl.room_type_ID=r.room_type_ID
AND (pl.day >= "2014-07-07"
AND pl.day <= "2014-07-11")
GROUP BY Room_ID,
Hotel_ID HAVING Days = 4
EDIT
How do I add 'No_of_Room' in SELECT that differentiates the room_types by the room number, example result of a single room:
Array
(
[Room_Price] => 160.00
[Days] => 4
[Hotel_ID] => 1
[Hotel_Name] => Hotel Alfa
[Room_Name] => Room type C
[Room_ID] => 3
[Max_Adults] => 3
[Max_Children] => 1
[No_of_Room] => 1 // What number of room does this room_type belongs to
)
Then I can show the results like:
EDIT
Rooms table
Rooms(
ID,
hotel_id
room_name,
max_Adults,
max_Children
);
-- Populate
INSERT INTO Rooms VALUES (1,1,"Room A",2,1),(2,1,"Room B",2,5),(3,1,"Room C",3,0);
INSERT INTO Rooms VALUES (1,2,"Room A",2,1),(2,2,"Room B",2,5),(3,3,"Room C",3,4);
EXAMPLES OF USING VIEWS TO MAKE THINGS NICER.
For this project authors may have aliases, for example one book may have "S. Lang" as the author, another might have "Serge Lang", the primary author is the main form (Serge Lang) and the secondaries are things like "S. Lang".
It is important to relate these, ideally I'd like a table with "AuthorId" and "PrimaryAuthorId" as columns, that way I could just select PrimaryAuthorId from it on AuthorId being equal to something.
To do this the view is defined as:
select
`BookSystem_AuthorList`.`AuthorId` AS `AuthorId`,
if((`BookSystem_AuthorList`.`duplicateOf` = 0),
`BookSystem_AuthorList`.`AuthorId`,
`BookSystem_AuthorList`.`duplicateOf`
) AS `PrimaryAuthorId`
from `BookSystem_AuthorList`;
Then
SELECT PrimaryAuthorId FROM BookSystem_PrimaryAuthorId WHERE AuthorId=10;
gives:
7
Which is much nicer for joining!
I then use this view to define another view (EditionAuthorsWithPrimaryId) - this gets the authors of an edition - and the primary author (I can then join to get names as needed)
select
`BookSystem_EditionAuthors`.`BindingId` AS `BindingId`,
`BookSystem_EditionAuthors`.`EditionId` AS `EditionId`,
`BookSystem_EditionAuthors`.`AuthorId` AS `AuthorId`,
`BookSystem_EditionAuthors`.`Position` AS `Position`,
(select
`BookSystem_PrimaryAuthorId`.`PrimaryAuthorId`
from `BookSystem_PrimaryAuthorId`
where (`BookSystem_PrimaryAuthorId`.`AuthorId` = `BookSystem_EditionAuthors`.`AuthorId`)
) AS `PrimaryAuthorId`
from `BookSystem_EditionAuthors`;
Now I can do:
SELECT * FROM BookSystem_EditionAuthorsWithPrimary WHERE EditionId=10;
BindingId, EditionId, AuthorId, Position, PrimaryAuthorId
10, 10, 10, 0, 7
Much nicer!
this next query is a great example
select
`BookSystem_BookList`.`BookId` AS `Id`,
`BookSystem_BookList`.`Title` AS `Name`,
`BookSystem_BookList`.`UserId` AS `UserId`,
`BookSystem_BookList`.`BookType` AS `Subtype`,
1 AS `IsBook`,0 AS `IsSeries`,
0 AS `IsAuthor`
from `BookSystem_BookList`
union
select
`BookSystem_SeriesList`.`SeriesId` AS `Id`,
`BookSystem_SeriesList`.`SeriesName` AS `Name`,
`BookSystem_SeriesList`.`UserId` AS `UserId`,
'' AS `Subtype`,
0 AS `IsBook`,
1 AS `IsSeries`,
0 AS `IsAuthor`
from `BookSystem_SeriesList`
union
select
`BookSystem_AuthorList`.`AuthorId` AS `Id`,
concat(
`BookSystem_AuthorList`.`AuthorSurname`,', ',`BookSystem_AuthorList`.`AuthorForename`,
ifnull(
(select concat(
' (AKA: ',
group_concat(
concat(
`BookSystem_AuthorList`.`AuthorSurname`,
', ',
`BookSystem_AuthorList`.`AuthorForename`
) separator '; '
),')'
) AS `AKA` from `BookSystem_AuthorList`
where
(`BookSystem_AuthorList`.`duplicateOf` = `Id`)
group by (`BookSystem_AuthorList`.`duplicateOf` = `Id`)
),'')) AS `Name`,
`BookSystem_AuthorList`.`UserId` AS `UserId`,
'' AS `SubType`,
0 AS `IsBook`,
0 AS `IsSeries`,
1 AS `IsAuthor`
from `BookSystem_AuthorList`
where (`BookSystem_AuthorList`.`duplicateOf` = 0) order by `Name`;
IS HUGE!
But now I can get all the things for UserId=1 easily:
mysql> SELECT * FROM BookSystem_Index WHERE UserId = 1;
+----+----------------------------------------+--------+-------------+--------+----------+----------+
| Id | Name | UserId | Subtype | IsBook | IsSeries | IsAuthor |
+----+----------------------------------------+--------+-------------+--------+----------+----------+
| 4 | A First Course in Calculus | 1 | Normal | 1 | 0 | 0 |
| 2 | A First Course in Real Analysis | 1 | Normal | 1 | 0 | 0 |
| 2 | Algebra | 1 | | 0 | 1 | 0 |
| 13 | Analysis II assignments | 1 | Assignments | 1 | 0 | 0 |
| 14 | Author Test | 1 | Normal | 1 | 0 | 0 |
| 8 | b, g | 1 | | 0 | 0 | 1 |
| 7 | b, g (AKA: t, lll; Teal, lll) | 1 | | 0 | 0 | 1 |
| 1 | Calculus of Several Variables | 1 | Normal | 1 | 0 | 0 |
| 4 | DuBois, Paul | 1 | | 0 | 0 | 1 |
| 1 | Lang, Serge (AKA: Lang, S. E. R. G. E) | 1 | | 0 | 0 | 1 |
| 5 | Linear Algebra | 1 | Normal | 1 | 0 | 0 |
| 3 | Morrey, C. B. | 1 | | 0 | 0 | 1 |
| 6 | MySQL | 1 | Normal | 1 | 0 | 0 |
| 7 | Principles of Mathematical Analysis | 1 | Normal | 1 | 0 | 0 |
| 2 | Protter, M. H. | 1 | | 0 | 0 | 1 |
| 5 | Rudin, Walter | 1 | | 0 | 0 | 1 |
| 10 | t | 1 | Normal | 1 | 0 | 0 |
| 3 | Test | 1 | | 0 | 1 | 0 |
| 12 | Test 1 | 1 | Normal | 1 | 0 | 0 |
| 11 | Test 4.4.2014 | 1 | Normal | 1 | 0 | 0 |
| 8 | Topology and Analysis | 1 | Normal | 1 | 0 | 0 |
| 3 | Undergraduate Algebra | 1 | Normal | 1 | 0 | 0 |
| 1 | Undergraduate Texts in Mathematics | 1 | | 0 | 1 | 0 |
| 9 | w | 1 | Normal | 1 | 0 | 0 |
+----+----------------------------------------+--------+-------------+--------+----------+----------+
24 rows in set (0.00 sec)
The optimiser sees the view properly, it wont generate the full view, it effectively substitutes the required selects.
(Taken from a testing DB, not production, hence weird names like "TESTING")
First, the room type selection needs to be framed correctly. The following join would probably work.
EDIT:
The query has been edited to return only properties with all three room types. It has also been joined with the plan table.
SELECT
COUNT(pl.day) AS Days,
p.property_ID AS Hotel_ID,
p.name AS Hotel_Name,
r.room_name AS Room_Name,
r.room_type_ID AS Room_ID,
r.max_adults as Max_Adults,
r.max_children as Max_Children
FROM property p
INNER JOIN room_type r
ON p.property_ID=r.property_ID
INNER JOIN plan pl
ON pl.room_type_ID=r.room_type_ID
AND (pl.day >= '2014-07-07' AND pl.day <= '2014-07-11')
WHERE EXISTS
(SELECT 1
FROM room_type r1
WHERE p.property_ID=r1.property_ID
AND r1.max_adults = 2 AND r1.max_children = 0)
AND EXISTS
(SELECT 1
FROM room_type r2
WHERE p2.property_ID=r2.property_ID
AND r2.max_adults = 4 AND r2.max_children = 2)
AND EXISTS
(SELECT 1
FROM room_type r3
WHERE P.PROPERTY_ID=R3.PROPERTY_ID
AND r3.max_adults = 2 AND r3.max_children = 1)
GROUP BY
p.property_ID,
p.name,
r.room_name,
r.room_type_ID,
r.max_adults,
r.max_children
HAVING
COUNT(pl.day) = 4;

MySQL Dynamic inner join for combining multiple rows into one?

I am creating a database with the tables below, where shop_id in hours refers to a an id in shop.
Preferably I would have a query to return all data in one row, in stead of needing to post-process a lot of rows to "merge" the result from hours so the end result looks like this.
+-------------------+---------+------+---------+----------------+----------+---------------+---------------+-----+-----+-----+-----+-----+-----+-----+
| name | address | zip | city | municipal | phone | lat | lng | day | day | day | day | day | day | day |
+-------------------+---------+------+---------+----------------+----------+---------------+---------------+-----+-----+-----+-----+-----+-----+-----+
| Coop Marked Budal | false | 7298 | Budalen | Midtre gauldal | 72436410 | 62.8837013245 | 10.4836997986 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
+-------------------+---------+------+---------+----------------+----------+---------------+---------------+-----+-----+-----+-----+-----+-----+-----+
Right now I have come to the query below, wich I feel there must be a better alternative to. So my question is: Is there really another solution to this?
Also, I've seen concat, but I want to avoid having to split strings later on when processing the data.
select shop.name, shop.address, shop.zip, shop.city, shop.municipal, shop.phone, shop.lat, shop.lng,
h.day, hh.day, hhh.day, hhhh.day, hhhhh.day, hhhhhh.day, hhhhhhh.day
from shop
/**
As it requires a unique table name, this was the solution I found.
Could this be shortened?
**/
inner join hours h on shop.id = h.shop_id and h.day = 1
inner join hours hh on shop.id = hh.shop_id and hh.day = 2
inner join hours hhh on shop.id = hhh.shop_id and hhh.day = 3
inner join hours hhhh on shop.id = hhhh.shop_id and hhhh.day = 4
inner join hours hhhhh on shop.id = hhhhh.shop_id and hhhhh.day = 5
inner join hours hhhhhh on shop.id = hhhhhh.shop_id and hhhhhh.day = 6
inner join hours hhhhhhh on shop.id = hhhhhhh.shop_id and hhhhhhh.day = 7;
Tables
shop
+----+-------------------+---------+------+---------+----------------+----------+---------------+---------------+----------+-----------+
| id | name | address | zip | city | municipal | phone | lat | lng | chain_id | county_id |
+----+-------------------+---------+------+---------+----------------+----------+---------------+---------------+----------+-----------+
| 1 | Test | false | 1234 | Test | Test | 12341234| 0.0000 | 0.0000 | 3 | 16 |
+----+-------------------+---------+------+---------+----------------+----------+---------------+---------------+----------+-----------+
hours
+-----+----------+----------+---------+
| day | open | close | shop_id |
+-----+----------+----------+---------+
| 1 | 09:00:00 | 18:00:00 | 1 |
| 2 | 09:00:00 | 18:00:00 | 1 |
| 3 | 09:00:00 | 18:00:00 | 1 |
| 4 | 09:00:00 | 18:00:00 | 1 |
| 5 | 09:00:00 | 18:00:00 | 1 |
| 6 | 09:00:00 | 20:00:00 | 1 |
| 7 | 14:00:00 | 20:00:00 | 1 |
+-----+----------+----------+---------+
You can also use a case .. when to do the pivot, and then group by the shop fields and use an aggregate function to process the day.
select
shop.NAME, shop.address, shop.zip, shop.city, shop.municipal, shop.phone, shop.lat, shop.lng,
MAX(CASE WHEN h.DAY = 1 THEN h.DAY ELSE 0 END) AS Day1,
MAX(CASE WHEN h.DAY = 2 THEN h.DAY ELSE 0 END) AS Day2,
MAX(CASE WHEN h.DAY = 3 THEN h.DAY ELSE 0 END) AS Day3,
MAX(CASE WHEN h.DAY = 4 THEN h.DAY ELSE 0 END) AS Day4,
MAX(CASE WHEN h.DAY = 5 THEN h.DAY ELSE 0 END) AS Day5,
MAX(CASE WHEN h.DAY = 6 THEN h.DAY ELSE 0 END) AS Day6,
MAX(CASE WHEN h.DAY = 7 THEN h.DAY ELSE 0 END) AS Day7
from shop
INNER JOIN HOURS h ON shop.id = h.shop_id
group by
shop.NAME, shop.address, shop.zip, shop.city, shop.municipal, shop.phone, shop.lat, shop.lng;
Just a note about what you want displayed in the day columns:
AFAIK if any of the hours rows for a shop : day is missing, your current query will drop the whole row? If you want this behaviour repeated, you will need to also add in a where clause.