Mysql retriving results from a list - mysql

I am trying to avoid making a huge amount of queries. I am sure that there is a simple solution that I don't know of. What I want to achieve is something like this
-------------------------------------------------------
| type | 06/03 | 08/03 | 15/03 | 04/04 |
-------------------------------------------------------
| single room | 0 | 2 | 3 | 0 |
| double room | 1 | 2 | 5 | 0 |
| suite | 2 | 2 | 1 | 2 |
-------------------------------------------------------
passing some room ids and a list of dates. is there anyway to do this on db side or do I have to go through each room and make a query for each day?
Thank you guys
//R

something like this?
SELECT room_type AS type, dt, count(*) FROM table_name GROUP BY room_type, dt;

Related

What is the best way to reduce MXN table search in MySQL

I have two MySQL tables called tasks and users. All I want to do is I don't want to display the tasks that is already done by a user in his panel. Suppose the task table has about 1000 entries and there are about 50000 users. Also the users and the tasks keep increasing.
One solution I can think of, 1st is creating a separate table of task x user size.
For example:
user table
+---------+--------+-------+
| user_id | fname | lname |
+---------+--------+-------+
| 1 | John | Smith |
| 2 | Steve | Mark |
+---------+--------+-------+
task table
+---------+-------------+---------------+
| task_id | task | task_duration |
+---------+-------------+---------------+
| 1 | Do task 1 | 1 hour |
| 2 | Do task 2 | 1 hour |
+---------+-------------+---------------+
Creating a separate table called display
+------------+---------+---------+
| display_id | task_id | user_id |
+------------+---------+---------+
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 2 | 1 |
| 4 | 2 | 2 |
+------------+---------+---------+
So only listed tasks will be shown to the particular user.
The problem is that This does not look like an efficient solution. How can I design table in this scenario in an efficient way. If not what are the other ways?

Selecting the most recent result from one table joining to another

I have two tables.
One table contains customer data, like name and email address. The other table contains a log of the status changes.
The status log table looks like this:
+-------------+------------+------------+
| customer_id | status | date |
+-------------+------------+------------+
| 1 | Bought | 2018-07-01 |
| 1 | Bought | 2018-07-02 |
| 2 | Ongoing | 2018-07-03 |
| 3 | Ongoing | 2018-07-04 |
| 1 | Not Bought | 2018-07-05 |
| 4 | Bought | 2018-07-06 |
| 4 | Not Bought | 2018-07-07 |
| 4 | Bought | 2018-07-08 | *
| 3 | Cancelled | 2018-07-09 |
+-------------+------------+------------+
And the customer data:
+-------------+------------+
| id | name | email |
+-------------+------------+
| 1 | Alex | alex#home |
| 2 | John | john#home |
| 3 | Simon | si#home |
| 4 | Philip | phil#home |
+-------------+------------+
I would like to select the customer's who have "Bought" in July (07). But exclude customers who's status has changed from "Bought" anything other most recently.
The result should be just one customer (Philip) - all the others have had their status change to something other than Bought most recently.
I have the following SQL:
SELECT
a.customer_id
FROM
statuslog a
WHERE
DATE(a.`date`) LIKE '2018-07-%'
AND a.status = 'Bought'
ORDER BY a.date DESC
LIMIT 1
But that is as far as I have got! The above query only returns one result, but essentially there could be more than one.
Any help is appreciated!
Here is an approach that uses a correlated subquery to get the most recent status record:
SELECT sl.customerid
FROM wwym_statuslog sl
WHERE sl.date = (SELECT MAX(sl2.date)
FROM wwym_statuslog sl2
WHERE sl2.customer_id = sl.customer_id AND
sl2.date >= '2018-07-01' AND
sl2.date < '2018-08-01'
) AND
sl.status = 'Bought'
ORDER BY sl.date DESC
LIMIT 1;
Notes:
Use meaningful table aliases! That is, abbreviations for the table names, rather than arbitrary letters such as a and b.
Use proper date arithmetic. LIKE is for strings. MySQL has lots of date functions that work.
In MySQL 8+, you would use ROW_NUMBER().

How do I write in a single query two different sum queries with different conditions?

I have a MySQL datatable items as below:
+----+-------+----------+----------+
| id | value | discount | type |
+----+-------+----------+----------+
| 1 | 20 | 1 | hardware |
| 2 | 40 | 0 | hardware |
| 3 | 60 | 1 | software |
| 4 | 30 | 1 | software |
+----+-------+----------+----------+
When discount is 1, this means that effectively the value is ZERO.
I want to get back the following results
+----------+----+
| software | 0 |
| hardware | 40 |
+----------+----+
I know how to do this in multiple queries.
SELECT type, SUM(value) from items where discount != 1 group by type
which gives me just
+----------+----+
| hardware | 40 |
+----------+----+
and then
SELECT type, 0 from items where discount = 1 group by type
which gives me
+----------+----+
| software | 0 |
| hardware | 0 |
+----------+----+
then i need to join these two tables to get the final result.
My question is :
is there a way I can accomplish the same result with just 1 query?
Thank you.
I think this is what you want
SELECT type, SUM(if(discount =1, 0,value)) from items group by type

MySQL - Alternative to GROUP BY without aggregate function?

Imagine an unordered table set up as below:
+----+------------+----------+-----------+
| ID | Project | Resource | StartDate |
+----+------------+----------+-----------+
| 1 | ExtraParts | Mark | 24/01 |
| 2 | ExtraParts | Sam | 22/01 |
| 3 | TimeLabour | Sally | 19/01 |
| 4 | TimeLabour | Sarena | 23/01 |
| 5 | Runway | Olly | 14/02 |
| 6 | Runway | Mary | 14/05 |
+----+------------+----------+-----------+
I would like to order by the earliest StartDate for each project, but still group the resources from each projects together(not sure if im explaining this right, but below is what I would like to achieve)
+----+-------------+-----------+-----------+
| ID | Project | Resource | StartDate |
+----+-------------+-----------+-----------+
| 1 | TimeLabor | Sally | 19/01 |
| 2 | TimeLabor | Sarena | 23/01 |
| 3 | ExtraParts | Sam | 22/01 |
| 4 | ExtraParts | Mark | 24/01 |
| 5 | Runway | Olly | 14/02 |
| 6 | Runway | Mary | 14/05 |
+----+-------------+-----------+-----------+
If I do ORDER BY StartDate, Project then the result will have jumbled up the projects. If i ORDER BY Project, StartDate then the result will be sorted alphabetically by project first and then sort by date within the same project(if that makes sense). As stated above, I would like to order by the earliest StartDate for each project while still grouping the projects together(not aggregate grouping, just one under the other).
Any help is greatly appreciated! :)
something like this? SQL FIDDLE to play with
SELECT project, resource, startdate
FROM testing
ORDER BY project, STR_TO_DATE(StartDate, '%d/%m')
basically your table is storing dates as a string and in order for you to order it you need to convert the strings to recognized dates... so the STR_TO_DATE() is a method to do that :)
You need to calculate the date used for the ordering:
select t.*
from table t join
(select project, min(startdate) as minsd
from table t
group by project
) tp
on t.project = tp.project
order by tp.minsd, t.project;
Note: this assumes that startdate is really stored as a date and not a string. If it is stored as a string, then you should convert it to a date first.

Database schema - Configurable fields?

I sell leads and charge my clients like so:
(Only one type of payment from the followings can be charged from a client)
Pay Per Lead:
$__ for the first __ leads per month
$__ for the next __ leads per month
$__ for the next __ leads per month
and so on...
Pay per Appointment:
$__ for the first __ leads per month
$__ for the next __ leads per month
$ __ for the next __ leads per month
and so on...
Pay per Percentage of Sale:
__% of the sale price (per sale)
My Question:
What are the best possible database design solutions in such cases?
What i have tried:
+---------+
| clients |
+---------+
| id |
| name |
+---------+
+---------------+
| deals |
+---------------+
| client_id |
| max_quantity |
| cost |
| unit_type |
+---------------+
So records for client with the id 1 might look like:
+-----------+--------------+---------------+-------------+
| client_id | max_quantity | cost_per_unit | unit_type |
+-----------+--------------+---------------+-------------+
| 1 | 10 | 10 | lead |
| 1 | 30 | 5 | lead |
| 1 | 100 | 2 | lead |
| 1 | 10 | 35 | appointment |
| 1 | 30 | 20 | appointment |
| 1 | 100 | 10 | appointment |
| 1 | 1000 | 5 | appointment |
| 1 | 0 | 50 | sale |
+-----------+--------------+---------------+-------------+
Now the above table means that:
$10 will be charged per lead upto 10 leads
$5 will be charged per lead upto 30 leads
$2 will be charged per lead upto 100 leads
$35 will be charged per appointment upto 10 leads
$20 will be charged per appointment upto 30 leads
$10 will be charged per appointment upto 100 leads
$5 will be charged per appointment upto 1000 leads
$50 will be charged per sale
Also i want to add x number of such rules (per lead, per appointment, per sale)
I personally don't think that my approach is one of the best solutions. Looking forward to hear for you cleaver folks! Thank you.
P.S. I know that unit_type can be further normalized but this is not the issue :)
Update
Maybe i can store serialized data?
Your proposed schema is a good start and has some merits. IMO the less elegant parts are the denormalized repetition of unit_type values and non-functional max_quantity value for sale.
Would suggest splitting deals into three tables rather than one. Would personally go with singular rather than plural table names** and begin with the same prefix so they are listed close to each other: Something like commission_lead, commission_appointment and commission_sale.
** [Lots of debate on this here]
Would also suggest including both lower and upper bands in each row. This does use more data than is strictly needed but think it is worth doing as it should make the table data more readable and simplify the calculation queries.
So the proposed new schema is:
+---------+
| client |
+---------+
| id |
| name |
+---------+
+-----------------+
| commission_lead |
+-----------------+
| client_id |
| min_quantity |
| max_quantity |
| cost_per_unit |
+-----------------+
+------------------------+
| commission_appointment |
+------------------------+
| client_id |
| min_quantity |
| max_quantity |
| cost_per_unit |
+------------------------+
+-----------------+
| commission_sale |
+-----------------+
| client_id |
| cost_per_unit |
+-----------------+
And the records for client_id = 1 are:
commission_lead
+-----------+--------------+--------------+---------------+
| client_id | min_quantity | max_quantity | cost_per_unit |
+-----------+--------------+--------------+---------------+
| 1 | 0 | 10 | 10 |
| 1 | 11 | 30 | 5 |
| 1 | 31 | 100 | 2 |
+-----------+--------------+--------------+---------------+
commission_appointment
+-----------+--------------+--------------+---------------+
| client_id | min_quantity | max_quantity | cost_per_unit |
+-----------+--------------+--------------+---------------+
| 1 | 0 | 10 | 35 |
| 1 | 11 | 30 | 20 |
| 1 | 31 | 100 | 10 |
| 1 | 101 | 1000 | 5 |
+-----------+--------------+--------------+---------------+
commission_sale
+-----------+---------------+
| client_id | cost_per_unit |
+-----------+---------------+
| 1 | 50 |
+-----------+---------------+
I make an assumption that the change is very rare (update/insert), most of the time you use select to calculate the cost, so I propose this design, the select to calculate cost is very simple
+-----------+--------------+---------------+---------------+--------------+------------+
| client_id | max_quantity | min_quantity | cost_per_unit | default_cost | unit_type |
+-----------+--------------+---------------+---------------+--------------+------------+
| 1 | 10 | 0 | 10 | 0 | lead|
| 1 | 40 | 10 | 5 | 100 | lead|
| 1 | 140 | 40 | 2 | 250 | lead|
| 1 | 10 | 0 | 35 | 0 | appointment|
| 1 | 40 | 10 | 20 | 350 | appointment|
| 1 | 140 | 40 | 10 | 950 | appointment|
| 1 | 1140 | 140 | 5 | 1950 | appointment|
| 1 | 0 | 0 | 50 | 0 | sale|
+-----------+--------------+---------------+---------------+--------------+------------+
select query looks like
select
default_cost + ($quantity - min_quantity) * cost_per_unit
from
table
where
unit_type = $unit_type
and (max_quantity >= $quantity or max_quantity = 0)
and $quantity >= min_quantity
IF you consider the cost calculations business logic that is likely to change in the future AND you dont need to filter/sort the table based on the calculation constants, I recommend having one column for rule_id, that pretty much works like your unit_type, and one varchar column called properties where all the specific values needed for that rule is stored with a separator.
You then retrieve the rules that apply for your client to your business logic and do your calculations there. If you need a new rule that suddenly takes 5 parameters, you don't need to change the database schema. Simply write code for a new rule_id in your business logic and you are good to go.
Of course, if you prefer to move calculation logic into stored procedures and/or need to filter or order by rule properties, I think you should go with separate columns for each rule parameter...