SELECT where no commissions - mysql

I have 2 tables.
account_receivables
commissions
account_receivables has many commissions
commissions has a foreign key towards account_receivables_id.
The way my application works is when account_receivables gets an insert it also calculates commissions for a group of sales reps, based on account_receivables.amount.
There were 2 months where it randomly missed 1 sales rep. So what I am try to do is find out all the account_receivables.id where commissions were missed.
Is there a straight SQL query for this? It is a Laravel app and I have tried the below with no luck:
$comms = DB::connection('mysqllocal')->table('commissions')
->select('account_receivables_id')
->whereNotIn('rep_group_number', [999999])
->groupBy('account_receivables_id')->get();
999999 being rep_group_number

Basically you are looking for all records from account_receivables that do not have a corresponding record in commissions.
A simple LEFT JOIN with a WHERE ... IS NULL should do it.
select ar.id
from account_receivables ar
left join commissions c on c.account_receivables_id = ar.id
where c.id is null
You did not give the full table structure in your question ; the above query assumes that the relation between both tables is as follows (adapt it if needed) :
commissions.account_receivables_id -> account_receivables.id

Related

Use SELECT through three table

I tried to write a query, but unfortunately I didn't succeed.
I want to know how many packages delivered over a given period by a person.
So I want to know how many packages were delivered by John (user_id = 1) between 01-02-18 and 28-02-18. John drives another car (another plate_id) every day.
(orders_drivers.user_id, plates.plate_name, orders.delivery_date, orders.package_amount)
I have 3 table:
orders with plate_id delivery_date package_amount
plates with plate_id plate_name
orders_drivers with plate_id plate_date user_id
I tried some solutions but didn't get the expected result. Thanks!
Try using JOINS as shown below:
SELECT SUM(o.package_amount)
FROM orders o INNER JOIN orders_drivers od
ON o.plate_id=od.plate_id
WHERE od.user_id=<the_user_id>;
See MySQL Join Made Easy for insight.
You can also use a subquery:
SELECT SUM(o.package_amount)
FROM orders o
WHERE EXISTS (SELECT 1
FROM orders_drivers od
WHERE user_id=<user_id> AND o.plate_id=od.plate_id);
SELECT sum(orders.package_amount) AS amount
FROM orders
LEFT JOIN plates ON orders.plate_id = orders_drivers.plate_id
LEFT JOIN orders_driver ON orders.plate_id = orders_drivers.plate_id
WHERE orders.delivery_date > date1 AND orders.delivery_date < date2 AND orders_driver.user_id = userid
GROUP BY orders_drivers.user_id
But seriously, you need to ask questions that makes more sense.
sum is a function to add all values that has been grouped by GROUP BY.
LEFT JOIN connects all tables by id = id. Any other join can do this in this case, as all ids are unique (at least I hope).
WHERE, where you give the dates and user.
And GROUP BY userid, so if there are more records of the same id, they are returned as one (and summed by their pack amount.)
With the AS, your result is returned under the name 'amount',
If you want the total of packageamount by user in a period, you can use this query:
UPDATE: add a where clause on user_id, to retrieve John related data
SELECT od.user_id
, p.plate_name
, SUM(o.package_amount) AS TotalPackageAmount
FROM orders_drivers od
JOIN plates p
ON o.plate_id = od.plate_id
JOIN orders o
ON o.plate_id = od.plate_id
WHERE o.delivery_date BETWEEN convert(datetime,01/02/2018,103) AND convert(datetime,28/02/2018,103)
AND od.user_id = 1
GROUP BY od.user_id
, p.plate_name
It groups rows on user_id and plate_name, filter a period of delivery_date(s) and then calculate the sum of packageamount for the group

SQL querying multiple tables for information

I have a little dilemma in joining data from 4 tables in one SQL query, I am using MySQL for the DB part and would appriciate any help you can give me.
Here is the task...
I have for tables with columns and data
Sale Items Owner Salesman
-------------- ----------- ----------- --------------
*Salesman_id Item_type *Owner_id *Salesman_id
*Owner_id Item_color Owner_name Salesman_name
Buyer_id *Owner_id
Price
I want to query these tables on the columns I have marked with emphases text. So I can get result like
Item type, Item color, Owner name, Salesman name, Salesman number.
I have gone through a countless number of iteration trying to achieve this both with JOIN and nested queries without sufficient result.
If there is a one-to-one relation you can use inner join
SELECT i.Item_type , i.Item_color ,o.Owner_name,sm.Salesman_name,sm.Salesman_id
FROM Salesman sm
INNER JOIN Sale s ON (s.Salesman_id = sm.Salesman_id )
INNER JOIN Owner o ON (s.Owner_id=o.Owner_id)
INNER JOIN Items i ON (i.Owner_id=o.Owner_id)
If there is one -to- many try with Left join
try this
SELECT Item_type, Item_color, Owner_name, Salesman_name, Sale.Salesman_id FROM Items
INNER JOIN Owner USING(Owner_id)
INNER JOIN Sale USING(Owner_id)
INNER JOIN Salesman ON Salesman.Salesman_id=Sale.Salesman_id
why doesn't the Items table have a primary key?
A solution when we're not joining, and you want it them to just display their values, you can do something like (I know this doesn't directly answer OP's question, but I'm getting there...)
SELECT sale.`salesman_id`,sale.`owner_id`,
items.`order_id`,
owner.`owner_id`,
salesman.`salesman_id`
FROM `Sale` sale,
`Items` items,
`Owner` owner,
`Salesman` salesman
And that should return everything.
However, your question states that we are joining. Could you put some data into something like SQLFiddle so I have some visual representation? and a brief summary of what you're trying to accomplish - as in where you want the joins?

Creating a query in mysql linking 2 tables and only displaying certain information

I have 2 tables, tbl_students & tbl_inv. The student table holds all information for students. I am creating an invoicing system to create and keep records for invoices (monthly) for the students. The tbl_inv can have multiple invoices for a single student but with a different date. I am trying to create an array which will list all the students with the latest invoice, total and status ordered by the newest invoice date at the top. I am fairly new to programming with mysql and php, so my apologies if my question sounds silly. This is what I have for the query.....
$query = "SELECT * FROM tbl_student
LEFT JOIN tbl_inv ON tbl_student.sid = tbl_inv.inv_sid
GROUP BY tbl_student.sid
ORDER BY tbl_inv.inv_date DESC";
This creates an array which has one line per student but doesn't display the latest invoice date and details.
If anyone can help I would be much appreciated :-)
(Addition pull from direct comments to existing answer)
This is the final query that works..
SELECT
S.*,
TI2.*
FROM
tbl_student S
LEFT JOIN ( SELECT
TI.inv_sid,
MAX(TI.inv_id) LatestInvoice
FROM
tbl_inv TI
GROUP BY
TI.inv_sid ) PreQuery
ON S.sid = PreQuery.inv_sid
LEFT JOIN tbl_inv TI2
ON PreQuery.inv_sid = TI2.inv_sid
AND PreQuery.LatestInvoice = TI2.inv_id
ORDER BY
TI2.inv_id ASC
I have students link with each other my using a field called f_link on the student table. If a student has a family member linked to them the f_link field shows the master id no. If there is no family link the field just shows a 0. With my invoicing system I am creating an invoice for a student and any family member linked to them. The current query will display no data for invoices for the family member, but they have been invoiced. I want to narrow this query down to only display students who have 0 in the f_link field.
Keep looking and learning querying... formatting and readability is a big plus for future maintenance. For this type of problem, ask what is the FIRST thing you need... in your case, on a per-student basis, what is the last invoice they had (regardless of the data).
select
TI.inv_sid,
MAX( TI.inv_date ) LatestInvoiceDate
from
tbl_inv TI
group by
TI.inv_sid
The above will give you one piece of the puzzle, and that is how many complex queries get built. From this, you then want the student's name, and invoice details about this most recent invoice. To do, the above query will be used in the next phase... in this case, it will get an "alias" for its result set to get the rest of the details.
select
S.*,
TI2.*
from
tbl_Student S
LEFT JOIN ( select
TI.inv_sid,
MAX( TI.invoicenumber ) LatestInvoiceNumber,
count(*) totalInvoicesForStudent,
sum( TI.Total ) as TotalAllInvoices,
sum( TI.Total - TI.AmountPaid) as OutstandingBalances
from
tbl_inv TI
group by
TI.inv_sid ) PreQuery
on S.sid = PreQuery.inv_sid
LEFT JOIN tbl_inv TI2
on PreQuery.inv_sid = TI2.inv_sid
AND PreQuery.LatestInvoiceNumber = TI2.invoiceNumber
where
s.F_Link = 0
order by
TI2.inv_date desc
So, to clarify above query
For EVERY Student (table listed first),
do a LEFT JOIN (all students regardless of ever yet having an invoice) to the "PreQuery" result set that has all students with their most recent invoice date).
If such an invoice record WAS found, do another LEFT JOIN to the invoice table AGAIN, but this time on the PreQuery "student id" and the "LatestInvoiceDate" determined for that user to the original invoice table.
Once those are all joined together, get all the fields from both the student table and the SECOND instance (TI2) invoice table for the invoice details.
Now, if you want ONLY students who HAD A MINIMUM of at least 1 invoice, just leave as "JOIN" instead of "LEFT JOIN".

SQL link 5 tables

Much more to it but there are 3 tables...
employees
employee_id
licenses
license_id
employee_id
companies
company_id
employee_id
SELECT * FROM employees
LEFT JOIN licenses
ON employees.employee_id = licenses.employee_id
LEFT JOIN companies
ON employees.employee_id = companies.employee_id
GROUP BY employees.employee_id
I can only get it so either licenses OR companies returns a value and the other returns NULL. How can I get it so BOTH tables return values? Seems so easy but it isn't working in this case and I can't figure out why...
EDIT: Here is some more info.
Not every employee has a license.
Not every employee has a company.
Would like to return employee_id license_id (if exists, else NULL) company_id (if exists, else NULL)
Take the case where an employee has both a license_id and a company_id. By removing one of the JOIN clauses, can return the corresponding value. However, when both are combined, only return the company_id and license_id returns NULL.
Weird, right? Any ideas or is more info needed?
DATA:
employee_id
1
2
3
employee_id license_id
1 1
2 1
3 2
employee_id company_id
1 1
2 1
3 2
SORRY FOR WASTING TIME
The table schema is screwed up and redundant. This was an inherited schema and I was just considering the SQL, not the underlying structure. Database needs restructuring.
This is very difficult to answer without seeing the data in the tables. So I'll make the assumption, that there are rows in each table that all have a single Employee_ID that is the same, so the joins work. While your testing this I would suggest picking one Employee_id to work with too, just to simplify the output while you test.
Based on my assumptions, I switched your queries to inner joins, this will only show rows that match on the Employee_id. I also used "aliasing". The single letter I put after each table pointer saves a lot of typing.
SELECT *
FROM employees e
INNER JOIN licenses l
ON e.employee_id = l.employee_id
INNER JOIN companies
ON e.employee_id = c.employee_id
GROUP BY employee_id
If you're new to SQL joins, this article may be helpful too. Best of luck!
There are alot of different JOIN types. My suggestion would be to do some reading about them to figure it out. You can use a FULL OUTER JOIN
SELECT *
FROM employees
FULL OUTER JOIN licenses
ON employees.employee_id = licenses.employee_id
FULL OUTER JOIN companies
ON employees.employee_id = companies.employee_id
GROUP BY employee_id
It is difficult to figure exactly what you want without seeing any data. But here is a handy visual explanation of SQL Joins. I keep it bookmarked for those times that I need some help.
http://www.codinghorror.com/blog/2007/10/a-visual-explanation-of-sql-joins.html
This is my favorite article on the subject.
http://www.codeproject.com/KB/database/Visual_SQL_Joins.aspx
Try
FULL OUTER JOIN

When to use a left outer join?

I don't understand the concept of a left outer join, a right outer join, or indeed why we need to use a join at all! The question I am struggling with and the table I am working from is here: Link
Question 3(b)
Construct a command in SQL to solve the following query, explaining why it had to employ the
(outer) join method. [5 Marks]
“Find the name of each staff member and his/her dependent spouse, if any”
Question 3(c) -
Construct a command in SQL to solve the following query, using (i) the join method, and (ii) the
subquery method. [10 Marks]
“Find the identity name of each staff member who has worked more than 20 hours on the
Computerization Project”
Can anyone please explain this to me simply?
Joins are used to combine two related tables together.
In your example, you can combine the Employee table and the Department table, like so:
SELECT FNAME, LNAME, DNAME
FROM
EMPLOYEE INNER JOIN DEPARTMENT ON EMPLOYEE.DNO=DEPARTMENT.DNUMBER
This would result in a recordset like:
FNAME LNAME DNAME
----- ----- -----
John Smith Research
John Doe Administration
I used an INNER JOIN above. INNER JOINs combine two tables so that only records with matches in both tables are displayed, and they are joined in this case, on the department number (field DNO in Employee, DNUMBER in Department table).
LEFT JOINs allow you to combine two tables when you have records in the first table but might not have records in the second table. For example, let's say you want a list of all the employees, plus any dependents:
SELECT EMPLOYEE.FNAME as employee_first, EMPLOYEE.LNAME as employee_last, DEPENDENT.FNAME as dependent_last, DEPENDENT.LNAME as dependent_last
FROM
EMPLOYEE INNER JOIN DEPENDENT ON EMPLOYEE.SSN=DEPENDENT.ESSN
The problem here is that if an employee doesn't have a dependent, then their record won't show up at all -- because there's no matching record in the DEPENDENT table.
So, you use a left join which keeps all the data on the "left" (i.e. the first table) and pulls in any matching data on the "right" (the second table):
SELECT EMPLOYEE.FNAME as employee_first, EMPLOYEE.LNAME as employee_last, DEPENDENT.FNAME as dependent_first, DEPENDENT.LNAME as dependent_last
FROM
EMPLOYEE LEFT JOIN DEPENDENT ON EMPLOYEE.SSN=DEPENDENT.ESSN
Now we get all of the employee records. If there is no matching dependent(s) for a given employee, the dependent_first and dependent_last fields will be null.
example (not using your example tables :-)
I have a car rental company.
Table car
id: integer primary key autoincrement
licence_plate: varchar
purchase_date: date
Table customer
id: integer primary key autoincrement
name: varchar
Table rental
id: integer primary key autoincrement
car_id: integer
bike_id: integer
customer_id: integer
rental_date: date
Simple right? I have 10 records for cars because I have 10 cars.
I've been running this business for 10 years, so I've got 1000 customers.
And I rent the cars about 20x per year per cars = 10 years x 10 cars x 20 = 2000 rentals.
If I store everything in one big table I've got 10x1000x2000 = 20 million records.
If I store it in 3 tables I've got 10+1000+2000 = 3010 records.
That's 3 orders of magnitude, so that's why I use 3 tables.
But because I use 3 tables (to save space and time) I have to use joins in order to get the data out again
(at least if I want names and licence plates instead of numbers).
Using inner joins
All rentals for customer 345?
SELECT * FROM customer
INNER JOIN rental on (rental.customer_id = customer.id)
INNER JOIN car on (car.id = rental.car_id)
WHERE customer.id = 345.
That's an INNER JOIN, because we only want to know about cars linked to rentals linked to customers that actually happened.
Notice that we also have a bike_id, linking to the bike table, which is pretty similar to the car table but different.
How would we get all bike + car rentals for customer 345.
We can try and do this
SELECT * FROM customer
INNER JOIN rental on (rental.customer_id = customer.id)
INNER JOIN car on (car.id = rental.car_id)
INNER JOIN bike on (bike.id = rental.bike_id)
WHERE customer.id = 345.
But that will give an empty set!!
This is because a rental can either be a bike_rental OR a car_rental, but not both at the same time.
And the non-working inner join query will only give results for all rentals where we rent out both a bike and a car in the same transaction.
We are trying to get and boolean OR relationship using a boolean AND join.
Using outer joins
In order to solve this we need an outer join.
Let's solve it with left join
SELECT * FROM customer
INNER JOIN rental on (rental.customer_id = customer.id) <<-- link always
LEFT JOIN car on (car.id = rental.car_id) <<-- link half of the time
LEFT JOIN bike on (bike.id = rental.bike_id) <<-- link (other) 0.5 of the time.
WHERE customer.id = 345.
Look at it this way. An inner join is an AND and a left join is a OR as in the following pseudocode:
if a=1 AND a=2 then {this is always false, no result}
if a=1 OR a=2 then {this might be true or not}
If you create the tables and run the query you can see the result.
on terminology
A left join is the same as a left outer join.
A join with no extra prefixes is an inner join
There's also a full outer join. In 25 years of programming I've never used that.
Why Left join
Well there's two tables involved. In the example we linked
customer to rental with an inner join, in an inner join both tables must link so there is no difference between the left:customer table and the right:rental table.
The next link was a left join between left:rental and right:car. On the left side all rows must link and the right side they don't have to. This is why it's a left join
You use outer joins when you need all of the results from one of the join tables, whether there is a matching row in the other table or not.
I think Question 3(b) is confusing because its entire premise wrong: you don't have to use an outer join to "solve the query" e.g. consider this (following the style of syntax in the exam paper is probably wise):
SELECT FNAME, LNAME, DEPENDENT_NAME
FROM EMPLOYEE, DEPENDENT
WHERE SSN = ESSN
AND RELATIONSHIP = 'SPOUSE'
UNION
SELECT FNAME, LNAME, NULL
FROM EMPLOYEE
EXCEPT
SELECT FNAME, LNAME, DEPENDENT_NAME
FROM EMPLOYEE, DEPENDENT
WHERE SSN = ESSN
AND RELATIONSHIP = 'SPOUSE'
In general:
JOIN joints two tables together.
Use INNER JOIN when you wanna "look up", like look up detailed information of any specific column.
Use OUTER JOIN when you wanna "demonstrate", like list all the info of the 2 tables.