query between 3 Mysql tables per time range - mysql

I am working on a small database that records rentals of different properties for different periods of time to different clients. I leave a summary example of the structures of my tables below.
+--------------+
| customer |
|--------------|
| id |
| name |
+--------------+
+--------------+
| property |
|--------------|
| id |
| number |
| address |
+--------------+
+--------------+
| rental |
|--------------|
| id |
| date_init |
| date_end |
| month_payment|
| customer_id |
| property_id |
+--------------+
What I am trying to find out now through a consultation is the following: in my rental table I keep the client, property and amount that I agree to cancel each month for the rental, so there are clients who rent different properties, during the year. How can I know how much money my clients have generated during a certain period of time, for example if I have the following records:
customer
+--------------+
| id | name |
|--------------|
| 1 | jhon doe|
| 2 | alex gs |
| 3 | martha |
+--------------+
property
+------------------------------------+
| id | number | address |
--------------------------------------
| 1 | 5643 | chicago |
| 2 | 1023 | toronto |
| 3 | 3445 | atlanta |
+------------------------------------+
rental
+-------------------------------------------------------------------+
| id | customer_id | property_id | date_init | date_end | amount |
---------------------------------------------------------------------
| 1 | 1 | 1 | 2019-01-05 | 2019-06-05 |3000 |
| 2 | 2 | 2 | 2019-04-10 | 2019-10-10 |1800 |
| 3 | 1 | 3 | 2019-02-14 | 2019-11-14 |1000 |
+-------------------------------------------------------------------+
then given as a parameter a period of time for example: 2019-01-01 to 2019-12-30 get only the records that match and have the following result:
+---------------------+
| customer | total |
|----------------------
| jhon doe | 24,000 |
| alex gs | 10,800 |
+---------------------+
In this case, the John Doe client has rented 2 properties the first for 5 months for an amount of 3000 total of 15000 and the other property for 9 months to 1000 total of 9000, so is it possible to make a query with this type of data? I don't have a query as an example yet, since I don't know how to deal with this problem. I am working on it, as soon as I have something I will update my question, thank you!

edited--
You need to use SUM() and a JOIN then specify the fields you want returned.
SELECT c.name AS customer, SUM(r.amount) AS total
FROM rentals r
INNER JOIN customer c ON c.id = r.customer_id
WHERE r.date_end >= $START AND r.date_end <= $END
GROUP BY r.customer_id
http://www.sqlservertutorial.net/sql-server-aggregate-functions/sql-server-sum/

Related

Left joins, i need an explanation about a code

i am watching a tutorial. There is a code which i don't understand what is supposed to do.
$sql = 'SELECT p.*,
a.screen_name AS author_name,
c.name AS category_name
FROM
posts p
LEFT JOIN
admin_users a ON p.author_id = a.id
LEFT JOIN
categories c ON p.category_id = c.id
WHERE
p.id = ?';
I read about the left joins but i didn't understand them. Can somebody please explain me the code i shared.
Thanks in advance!
Imagine you have two tables. One that stores the information about the programmers on your website, and the other table that keeps track of their online purchases.
PROGRAMMERS Table
+--------------------------------------------+
| ID | NAME | AGE | ADDRESS | SALARY |
+----+----------+-----+-----------+----------+
| 1 | Desire | 32 | 123 fake s| 3000.00 |
| 2 | Jamin | 25 | 234 fake s| 2500.00 |
| 3 | Jon | 23 | 567 fake s| 2000.00 |
| 4 | Bob | 30 | 789 fake s| 1500.00 |
| 5 | OtherGuy | 31 | 890 fake s| 1000.00 |
| 6 | DudeMan | 32 | 901 fake s| 500.00 |
+--------------------------------------------+
PURCHASES Table
+---------------------------------------------+
| ORDER_ID | PROG_ID | DATE | PRICE |
+-------------+---------+---------------------|
| 1 | 1 | 1-1-2017 | 100 |
| 2 | 2 | 1-2-2017 | 200 |
| 3 | 6 | 1-3-2017 | 300 |
+---------------------------------------------|
You decide you need to make a new table to consolidate this information to a table that contains
certain columns you want.
For example, you figure it would be nice for shipping purposes to have a table
that has the ID, the NAME, the PRICE, and the DATE columns.
Currently, the tables we have don't display all of that in a single table.
If we were to LEFT JOIN these tables, we would end up filling the desired columns
with NULL values where there is no information to join.
SELECT ID, NAME, PRICE, DATE
FROM PROGRAMMERS
LEFT JOIN PURCHASES
ON PROGRAMMERS.ID = PURCHASES.PROG_ID;
Notice that I'm selecting the columns I want from the starting table, then joining the right table
even though there might be missing information.
RESULTING TABLE
+-------------------------------------+
| ID | NAME | PRICE | DATE |
+----+----------+-----------------+---+
| 1 | Desire | 100 | 1-1-2017 |
| 2 | Jamin | 200 | 1-2-2017 |
| 3 | Jon | NULL | NULL |
| 4 | Bob | NULL | NULL |
| 5 | OtherGuy | NULL | NULL |
| 6 | DudeMan | 300 | 1-3-2017 |
+-------------------------------------+
For a visual representation of the difference between SQL JOINs check out
https://www.codeproject.com/Articles/33052/Visual-Representation-of-SQL-Joins .

mysql same price mismatch column value

Good afternoon everyone,
I wonder if I can get help with this example in a database.
I have listings delivered as:
------------------------------------
| Id | name | price |
-------------------------------
| 1 | Hawaii | 20.58 |
| 2 | Hawaii VIP | 45.58 |
| 3 | Aruba | 13.58 |
| 4 | Aruba VIP | 34.58 |
| 5 | Japon | 14.58 |
| 6 | Japon VIP | 34.58 |
| 7 | Alemania | 14.58 |
| 8 | Alemania VIP | 14.58 |
But I need them to be shown as follows:
-----------------------------------------------------
| Id | name | price basic | price vip
-----------------------------------------------------
| 1 | Hawaii | 20.58 | 45.34 |
| 5 | Japon | 14.58 | 34.58 |
etc etc etc
What I need are the two prices of the same country in a different column in the same query.
As I can catch the "VIP" based on this field and put it in a column with its value
It would be better to store IS_VIP as a separate column in the first table instead of adding it to the name, but since it's not a perfect world, you could solve it like this until then. :)
SELECT
t.Id,
t.name,
t.price as "price basic",
v.price as "price VIP"
FROM YourTable t
JOIN YourTable v ON v.name = CONCAT(t.name, ' VIP')
Sql Fiddle Example

Finding MAX Date of Two Fields in an Access Query

In my access database, we keep track of two sets of dates. One set is for date of membership dues payments, the other set is date of other contributions (a non-membership donation.) There are multiple dates for each person depending on number of payments made for each type.
Example:
+----+---------------+---------------+
| ID | Dues_Date | Cont_Date |
+----+---------------+---------------+
| 1 | 01/01/15 | 09/12/11 |
| | 01/01/14 | |
| | 01/01/13 | |
| 2 | 07/30/14 | 06/20/13 |
| | | 11/12/11 |
+----+---------------+---------------+
First I needed to know the most recent payment for each of the two fields so I ran a query that tells me the MAX (most recent) date for each field.
Example Query:
+----+---------------+---------------+
| ID | Max Dues_Date | Max Cont_Date |
+----+---------------+---------------+
| 1 | 01/01/15 | 09/12/11 |
| 2 | 07/30/14 | 06/20/13 |
| 3 | 02/11/13 | 09/16/14 |
| 4 | 07/30/12 | 06/20/11 |
| 5 | 12/13/13 | 11/12/14 |
+----+---------------+---------------+
Now I need a third field in the same query to compare the results of the first two fields and show which is the MAX of those two.
I have column 2 and 3 in the query; how can I take that and create column 4 in the same query?
Example Query:
+----+---------------+---------------+-----------------+
| ID | Max Dues_Date | Max Cont_Date | Max Date(DD&CD) |
+----+---------------+---------------+-----------------+
| 1 | 01/01/15 | 09/12/11 | 01/01/15 |
| 2 | 07/30/14 | 06/20/13 | 07/30/14 |
| 3 | 02/11/13 | 09/16/14 | 09/16/14 |
| 4 | 07/30/12 | 06/20/11 | 07/30/12 |
| 5 | 12/13/13 | 11/12/14 | 11/12/14 |
+----+---------------+---------------+-----------------+
Try adapting this to your own scenario:
SELECT tblTest.DueDate, tblTest.ContDate, [DueDate]-[ContDate] AS Test, IIf([Test]<0,[ContDate],[DueDate]) AS MaxRes
FROM tblTest;
"Test" finds which is the later date, ContDate or Due Date. The IIf statement selects the later date.
Does this help?

MySQL JOIN 3 tables using multiple columns/keys

Complete newbie to mySQL. So any help will be appreciated.
I have 3 tables -- carts, users, actions.
carts:
+------------+-------------+-------+
| cartId | session_id | userId|
+------------+-------------+-------+
users:
+----------+-------------+
| usedId | email |
+----------+-------------+
actions:
+-------------+------------------+---- ---------+
| session_id | impressionAction | impressionId |
+-------------+------------------+-----+--------+
In carts, there is one session_id per line.
In users, there is one userId per line.
In actions, there are multiple lines per session_id counting for all the actions for that session.
I would like to JOINthe three tables getting the output to be something like
+------+-------------+--------+------------------+--------------+-------+
userId | session_id | cartId | impressionAction | impressionId | email |
+------+-------------+--------+------------------+--------------+-------+
Where there will be multiple lines per userId and session_id; essentially a flattened file. I think if we JOIN carts and users on userId resulting in say A and then JOIN A and actions' onsession_id`, we are home.
A sample expected output is:
+------------+-------------+--------+------------------+--------------+---------+
userId | session_id | cartId | impressionAction | impressionId | email |
+------------+-------------+--------+------------------+--------------+---------+
| 1234 | abc3f45 | 0001 | LOGIN | 2032 |ab#yc.com|
| 1234 | abc3f45 | 0001 | ADD | 4372 |ab#yc.com|
| 1234 | abc3f45 | 0001 | ADD | 4372 |ab#yc.com|
| 1234 | abc3f45 | 0001 | SENDMAIL | ab#yc.com |ab#yw.com|
| 4567 | def4rg4 | 0002 | LOGIN | 2032 |db#yw.com|
| 4567 | def4rg4 | 0002 | ADD | 4372 |db#yw.com|
| 4567 | def4rg4 | 0002 | REMOVE | 3210 |db#yw.com|
+------------+-------------+--------+------------------+--------------+---------+**
I don't know how to JOIN 3 tables without one common key. I don't even know what type of join it is called.
Essentially, we are trying to join 3 tables with non-overlapping keys, gathering one common key through the first JOIN and then joining the intermediate with the third one. Is this called a CROSS JOIN? If no, is there a name?
Taken from your comment above
A USER may select many products, add them to their CART; a single
USER may have multiple CARTS and at the end of the event, they can
EMAIL the cart to themselves; the ACTIONS of the user are stored in
the actions table
This is how I see the structure (having in mind your data)
+---------------------+ +---------------------+ +---------------------+
| users | | carts | | actions |
+---------------------+ +---------------------+ +---------------------+
| user_id [PK] |--| | cart_id [PK] | | impression_id [PK] |
| email | |--| user_id [FK] | | action_name |
| | | product_id [FK] | |--| session_id [FK]* |
+---------------------+ | session_id [FK]* |--| | |
| | +---------------------+
+---------------------+
As you can see above, I'm joining first with carts and them with actions because only the table carts has both, user and session data.
The [FK]* next to the session_id on carts and actions could seem as a foreign key but in this case it's not - 'cause there's no separate table for sessions where it would be placed as an PK (primary key)
You asked about join - it is the same as inner join. INNER JOIN creates a new result table by combining column values of two tables (A and B) based upon the join-predicate. The query compares each row of A with each row of B to find all pairs of rows which satisfy the join-predicate.
This is a possible content of the tables
+------------------------+
| users |
+------------------------+
| id | email |
+------+-----------------+
| 1 | first#mail.org |
| 2 | second#mail.org |
| 3 | third#mail.org |
+------+-----------------+
+------------------------------------------+
| carts |
+------------------------------------------+
| id | user_id | product_id | session_id |
+------+---------+------------+------------+
| 1 | 1 | 5 | 1aaaa |
| 2 | 2 | 5 | 2ffff |
| 3 | 3 | 8 | 3ddddd |
| 4 | 1 | 5 | 1aaaaa |
| 5 | 3 | 9 | 3bbbbb |
| 6 | 1 | 6 | 1ccccc |
+------+---------+------------+------------+
+-------------------------------+
| actions |
+-------------------------------+
| id | name | session_id |
+------+-----------+------------+
| 1 | ADD | 1aaaa |
| 2 | ADD | 2ffff |
| 3 | SENDMAIL | 3ddddd |
| 4 | ADD | 3ddddd |
| 5 | SENDMAIL | 2ffff |
| 6 | ADD | 1aaaaa |
| 7 | REMOVE | 3ddddd |
| 8 | ADD | 1ccccc |
| 9 | ADD | 3bbbbb |
| 10 | SENDMAIL | 3bbbbb |
+------+-----------+------------+
As you can see, there are six products in the table carts and exactly six add actions in the table actions. Furthermore, as you can see user with an id=1 bought three products but not at the same time, since there are two sessions; user with an id=3 as well, bought these two products in different times etc...
The SQL statement
SELECT u.user_id, c.session_id, c.cart_id, a.impression_id, a.action_name, u.email
FROM users AS u
INNER JOIN carts AS c ON c.user_id = u.user_id
INNER JOIN actions AS a ON a.session_id = c.session_id
ORDER BY u.user_id, c.session_id, c.cart_id
Results:
+---------+------------+---------+---------------+-------------+-----------------+
| user_id | session_id | cart_id | impression_id | action_name | email |
+---------+------------+---------+---------------+-------------+-----------------+
| 1 | 1aaaa | 1 | 1 | ADD | first#mail.org |
| 1 | 1aaaa | 1 | 6 | ADD | first#mail.org |
| 1 | 1aaaa | 4 | 1 | ADD | first#mail.org |
| 1 | 1aaaa | 4 | 6 | ADD | first#mail.org |
| 1 | 1cccc | 6 | 8 | ADD | first#mail.org |
| 2 | 2ffff | 2 | 5 | SENDMAIL | second#mail.org |
| 2 | 2ffff | 2 | 2 | ADD | second#mail.org |
| 3 | 3bbbb | 5 | 9 | ADD | third#mail.org |
| 3 | 3bbbb | 5 | 10 | SENDMAIL | third#mail.org |
| 3 | 3dddd | 3 | 3 | SENDMAIL | third#mail.org |
| 3 | 3dddd | 3 | 4 | ADD | third#mail.org |
| 3 | 3dddd | 3 | 7 | REMOVE | third#mail.org |
+---------+------------+---------+---------------+-------------+-----------------+
Note: There's no guarantee for session uniqueness.
(Updated) Working SQL Fiddle
UPDATE: (Finding and deleting duplicates)
I've updated the SQL Fiddle in order to simulate duplicate records (when user added the same product within the same session). With the following statement you'll be able to retrieve those duplicated rows.
SELECT c.card_id, c.user_id, c.product_id, c.session_id, a.action_name, a.impression_id
FROM cards As c
INNER JOIN actions AS a ON a.session_id = c.session_id
GROUP BY c.user_id, c.product_id, c.session_id, a.action_name
HAVING count(*) > 1
Results:
+---------+------------+------------+------------+-------------+-----------------+
| card_id | user_id | product_id | session_id | action_name | impression_id |
+---------+------------+------------+------------+-------------+-----------------+
| 1 | 1 | 5 | 1aaaa | ADD | 1 |
| 6 | 1 | 6 | 1cccc | ADD | 8 |
+---------+------------+------------+------------+-------------+-----------------+
In the SELECT part of the statement above you may omit everything except card_id and impression_id. Deleting these two duplicates in one statement is a bit tricky since you can't modify the same table selected in a sub-query within the same query. I would avoid the tricky part in this case (which involves another inner sub-query) and would delete duplicates using separate statements as following
-- delete duplicates from cards
--
DELETE FROM WHERE card_id IN (1,6)
-- delete duplicates from actions
--
DELETE FROM WHERE card_id IN (1,8)
Even better, you could check if the user already has been added a selected product and don't add it twice.
Excuse my MySql syntax, as I don't know it :-p But this is the idea
SELECT u.userId, a.session_id, c.cartId, a.impressionAction, a.impressionId, u.email
FROM Carts c
JOIN Users u on u.userId = c.UserId
JOIN Actions a on a.session_id = c.session_id
This will just merge everything together, and you'll have duplicate cart records if you have many to 1 relationships

Including a value once in a summed SSRS group

I have a data source which is pulling in event attendance information which looks like the following table.
Note that one booking can contain multiple attendees, causing duplication in the Amount column.
+------------+-----------+---------------+----------+
| Date | Booking | Booking Price | Attendee |
+------------+-----------+---------------+----------+
| 01/01/2011 | Booking 1 | £300.00 | Alice |
| 01/01/2011 | Booking 1 | £300.00 | Bob |
| 01/01/2011 | Booking 1 | £300.00 | Dave |
| 01/01/2011 | Booking 2 | £200.00 | Frank |
| 01/01/2011 | Booking 2 | £200.00 | Julie |
| 02/01/2011 | Booking 3 | £100.00 | Anne |
+------------+-----------+---------------+----------+
The Report should end up a bit like this:
+------------+-----------+---------+
| Date | Booking | Amount |
+------------+-----------+---------+
| 01/01/2011 | Booking 1 | £300 |
| | Alice | |
| | Bob | |
| | Dave | |
+------------+-----------+---------+
| | Booking 2 | £200 |
| | Frank | |
| | Julie | |
+============+===========+=========+
| TOTAL FOR 01/01/2011 | £500 |
| |
| |
+============+===========+=========+
| 02/01/2011 | Booking 3 | £100 |
| | Anne | |
+============+===========+=========+
| TOTAL FOR 02/01/2011 | £100 |
| |
| |
+============+===========+=========+
(That pretty much exhausts my ascii-art table skills!)
The problem I have is that because the amount is showing for each delegate, the aggregate functions count them all, so date for 01/01/2011 shows as £1300, instead of £500
I don't need any values next to the attendees, so I could pull it in a separate data set, but I can't seem to add a table into a tablix cell, so don't know how that would work.
The version of SSRS is key here. In SSRS 2008R2, you can now nest aggregate functions:
So this would now be a valid expression:
=SUM(FIRST(Fields!BookingPrice.Value , "BookingGroupName") , "DateGroupName")
If you aren't yet on 2008R2 then you can do some tricks with embedded code to keep a running total: http://beyondrelational.com/blogs/jason/archive/2010/07/03/aggregate-of-an-aggregate-function-in-ssrs.aspx
The key here is that you add to the total in the embedded code once per group. Then retrieve the total and clear it out at the end of the group.