Join two queries where one is grouped - php

I'm creating simple PHP / Laravel app and I have reached a problem:
I need to somehow join 2 queries, but I am not sure how to.
I could do it with some messy PHP loops, but I know that's not the right approach.
my queries in Laravel's code looks:
$cars = Car::get();
$drives = Drive::select(DB::raw('car_id, max(odometer) as odometer'))->groupBy('car_id')->get();
in plain SQL something like:
$cars = 'SELECT * FROM cars';
$drives = 'SELECT car_id, max(odometer) as odometer FROM drive GROUP BY car_id';
(drive)'car_id' = (cars)'id'
Update: Forgot to mention: I have 'odometer' field in 'car' and get max('odometer') from drives, so if there is something returned from 'drives' it should overwrite the one returned from 'car'
DRIVE:
id
car_id
user_id
odometer
liters_filled
route
is_private
is_refill
is_full
checque
date
deleted_at
created_at
updated_at
CARS:
id
title
plate_number
year
tank_size
odometer
user_id
deleted_at
created_at
updated_at
Thank you for your time and help!

To be honest I'm not 100% on what you are asking but you could try the following:
SELECT cr.id ,
dr.oodometer
FROM Car cr
INNER JOIN (SELECT dr.car_id,MAX(dr.oodometer) AS oodometer
FROM Drive dr
GROUP BY car_id ) dr ON dr.car_id = cr.id

SELECT cars.*, max(driver.oodometer) as odometer FROM cars
INNER JOIN driver on cars.id=driver.car_id
group by driver.car_id
This query will join the 2 tables for you and get you the info. The table names i used are your variable names for the sake of the example.
Edit for Laravel:
In config/database.php at mysql change :
'strict' => true,
to false.

Related

Selecting from SQL database where row exists with user id then get all other rows with similar value

I'm not sure why but I'm hitting an absolute wall trying to come up with this select statement. Maybe there is a PHP/MYSQL function that I'm not familiar with that would help. The idea is simple for this user management software: there are managers, and managers can (but do not have to) share clients. Amongst the manager and shared client relationship, one of the managers can be assigned as a lead. So here's how the basic example of what the database looks like for 1 client that is shared between 2 managers and assigned, and another client that is also shared but NOT assigned (represented by zero).
DROP TABLE IF EXISTS clients;
CREATE TABLE clients
(client_id SERIAL PRIMARY KEY
,client_name VARCHAR(12) UNIQUE
);
INSERT INTO clients VALUES
(555,'Jimmy'),
(789,'Tyler');
DROP TABLE IF EXISTS managers;
CREATE TABLE managers
(manager_id SERIAL PRIMARY KEY
,manager_name VARCHAR(12)UNIQUE
);
INSERT INTO managers VALUES
(123,'Michael'),
(456,'David');
DROP TABLE IF EXISTS relationships;
CREATE TABLE relationships
(client_id INT NOT NULL
,manager_id INT NOT NULL
,assigned INT NOT NULL
,PRIMARY KEY(client_id,manager_id)
);
INSERT INTO relationships VALUES
(555, 123, 0),
(555, 456, 1),
(789, 123, 0),
(789, 456, 0);
To get to the point: the statement I'm trying to make is for a manager to be shown all the clients that he has a relationship with, but are NOT assigned to him or anyone else on his team, i.e. select all of my clients where no one is assigned as the lead.
Expected input: Show all clients that manager 123 has a relationship with, but have yet to be assigned to any manager
Expected result: client 789
Happy to clarify as I can see this being overtly confusing as described.
SELECT c.*
FROM managers m
JOIN relationships r
ON r.manager_id = m.manager_id
JOIN clients c
ON c.client_id = r.client_id
LEFT
JOIN relationships x
ON x.client_id = c.client_id
AND x.assigned = 1
WHERE m.manager_id = 123
AND r.assigned = 0
AND x.client_id IS NULL;
+-----------+-------------+
| client_id | client_name |
+-----------+-------------+
| 789 | Tyler |
+-----------+-------------+
So you will have to start with finding all clientid's from the manager in RELATIONS, but remove all that have a manager assigned already.
Depending on the size of the table you might want to rewrite this, but here is one approach:
1) Get all clientids that have no manager:
SELECT R1.client_id, SUM(R1.assigned) as sumassigned FROM relationships AS R1 GROUP BY R1.client_id HAVING ( SUM(R1.assigned) = 0)
Now it is easier, you just join, eg:
SELECT R2.client_id, R2.manager_id FROM relationships AS R2
INNER JOIN
(SELECT R1.client_id, SUM(R1.assigned) as sumassigned FROM relationships AS R1 GROUP BY R1.client_id HAVING ( SUM(R1.assigned) = 0) ) AS DRVNOMANAGER
ON (R2.client_id = DRVNOMANAGER.client_id)
WHERE (R2.manager_id = 123)
Not tested. (meaning you might have to fix it)
The idea is to create a derived (temp) table containing all clients without a manager, then do an inner join on your original question ("what clients does this manager 123 know that do not have another assigned)
Does that solve your problem?
PS: Such things are much easier solved in PHP, but if your dataset is huge, that is not feasible.
OP asked for clientnames, so just add that:
SELECT R2.client_id, R2.manager_id, C.client_name FROM relationships AS R2
INNER JOIN
(SELECT R1.client_id, SUM(R1.assigned) as sumassigned FROM relationships
AS R1 GROUP BY R1.client_id HAVING ( SUM(R1.assigned) = 0) ) AS DRVNOMANAGER
ON (R2.client_id = DRVNOMANAGER.client_id)
INNER JOIN clients AS C ON (C.client_id = R2.client_id)
WHERE (R2.manager_id = 123)
And last request: removed deleted relations:
Simply add a WHERE clause to the inner DRVNOMANAGER with your restriction on the rows that are used in the GROUP BY. eg:
SELECT R2.client_id, R2.manager_id, C.client_name FROM relationships AS R2
INNER JOIN
(SELECT R1.client_id, SUM(R1.assigned) as sumassigned FROM relationships
AS R1 WHERE (NOT(R1.deleted = 1) ) GROUP BY R1.client_id HAVING ( SUM(R1.assigned) = 0) ) AS DRVNOMANAGER
ON (R2.client_id = DRVNOMANAGER.client_id)
INNER JOIN clients AS C ON (C.client_id = R2.client_id)
WHERE (R2.manager_id = 123)
==============================================
THIS WAS MY OLD ANSWER. NOT RELEVANT ANYMORE.
"select all of my clients where no one is assigned as the lead."
If I read you well that means: Get all clientid from RELATIONS where some managerid is given, AND assigned=0. (assigned=0 meaning "no one is assigned as the lead.")
Is that correct?
Then you end up with something like this (for managerid 123):
SELECT R.clientid, C.clientname FROM RELATIONSHIPS AS R WHERE ( (R.managerid = 123) AND (R.assigned=0))
INNER JOIN CLIENTS AS C ON (C.clientid = R.clientid)
I removed the spaces in the columnnames because I hate spaces in columnnames.

MY SQL Query for salary sheet

I have 3 tables in MYSQL From 2 different database running in same server
and my expected Output is
MY attempt of query is
SELECT `biometric`.`Empid`,
,`name`,`location`,`basic`,`hra`,`conveyance`,`total salary`,sum(DISTINCT DATEDIFF(LEAST(`endDate`,'$monthEnd' ),GREATEST(`startdate`,'$monthStart'))+1) as leaves FROM `biometric`.`biometric`,`biometric`.`employee` JOIN `lms`.`leaves` WHERE `biometric`.`empid`= `employee`.`empid` AND `employee`.`empid` = `leaves`.`id` AND
`startdate`<='$monthEnd' AND `endDate`>= '$monthStart' AND `leaves`.`status` = '3'
GROUP BY `Empid`
and here status =3 is approved leave and 1 is non approved leave.
and my out put coming is
Thanks in Advance...
You can try below query, even I did not test it so if you get any error then you can create an sqlfiddle so that I can correct it.
Basic concept is that you need to use left join for lms.leaves table as you need all employee details even they did not took leave under status 3.
SELECT bmt.`Empid`,`name`,`location`,`basic`,`hra`,`conveyance`,`total salary`,
IFNULL(SUM(DISTINCT DATEDIFF(LEAST(`endDate`,'$monthEnd' ),GREATEST(`startdate`,'$monthStart'))+1),0) AS LEAVES
FROM BM.`biometric` AS bmt
JOIN BM.`employee` AS emp ON bmt.`empid`= emp.`empid`
LEFT JOIN `lms`.`leaves` AS lvs ON emp.`empid` = lvs.`id` AND lvs.`status` = '3' AND `startdate`<='$monthEnd' AND `endDate`>= '$monthStart'
GROUP BY bmt.`Empid`;

joining tables and get count from one table in yii framework

I am new to yii and I faces a small issue.In one of my project,I have two models employees and departments.In admin side,while listing the departments(grid view),I have to show the number of employees in each department.I have done the page for listing the departments but cannot able to add the number of employees in each department.
my employee table consists of :
empid
deptid
empname
my department table consists of:
deptid
deptname
In mysql (phpmyadmin interface) I can write a query to combine the two tables and get the correct result:
SELECT D. * , count( E.deptid) AS emp_count
FROM department AS D
LEFT JOIN employee AS E ON D.id = E.deptid
GROUP BY D.id
The result of this query:
id name emp_count
1 Accounts 0
2 Development 2
3 Quality Control 1
4 Operations 0
5 Human Resources 2
6 System 1
How can I implement this in grid view in yii?
below is the code for how to do join in cgridview,
add this code in your search function.
$criteria->with = array('relation_name');
$criteria->addCondition('relation_name.column_name ='.comparision_variable);
$model = Model::model()->findAll($criteria);
add following code in above answer
$criteria->select = 't. * , count( employee.deptid)';
$criteria->group = 't.id';
first line will select the columns you needed.
Second line is for group by.

MySQL very simple join example requested with subtable

I keep falling back into questions with MySQL joining.
And I would like to request a very simple example I could use to continue my journey of understanding learning the MySQL syntax.
Let's say I got the following table's
test_testtable
testtable_id
testtable_name
testtable_user
testtable_option
testtable_textfield
test_testlink
testlink_id
testlink_link
testlink_address
test_address
address_id
address_name
address_phone
address_email
address_street
address_city
address_zip
I would like to make a selection like :
SELECT * (lets say I would define the fields) FROM `test_testable`
JOIN `test_testtable`.`testtable_id` = `test_testlink`.`testlink_link`
AND
JOIN `test_testlink`.`testlink_addres` = `test_address`.`address_id`
WHERE `user_id` = 5
Hence the linking structure is like:
test_testtable.testtable_id = leading
table test_testlink is a table to link the table test_testtable and test_address
And linking table test_testlink uses the field testlink_link to link to the table test_testtable, and uses the field testlink_address to link to the table test_address
This does not work. FOR ME.. Since I continuously seem to fail of catching the correct syntax logic.
So I hope that someone could give me a small example of how to correctly implement such a simple yet critical query!
TIAD!!
A general approach :
SELECT table1.* FROM table1
JOIN table2 ON table2.id_table1 = table1.id
JOIN table3 ON table3.id_table2 = table2.id
WHERE table1.id = 10
For your purpose :
SELECT * (lets say I would define the fields) FROM `test_testable`
JOIN `test_testlink` ON `test_testtable`.`testtable_id` = `test_testlink`.`testlink_link`
JOIN `test_address` ON `test_testlink`.`testlink_addres` = `test_address`.`address_id`
WHERE `user_id` = 5
Please read the reference
You are using wrong syntax. You should mention which tables to join first then based on which fields.
SELECT * (lets say I would define the fields) FROM `test_testable`
INNER JOIN test_testlink
ON `test_testtable`.`testtable_id` = `test_testlink`.`testlink_link`
INNER JOIN `test_address`
ON `test_testlink`.`testlink_addres` = `test_address`.`address_id`
AND `test_testtable`.`user_id` = 5
select * from testlink JOIN testtable ON testlink.tableid = testtable.ID
JOIN testaddress ON testlink.addressid = testaddress.ID
WHERE testtable.ID = 5

MySQL Join and create new column value

I have an instrument list and teachers instrument list.
I would like to get a full instrument list with id and name.
Then check the teachers_instrument table for their instruments and if a specific teacher has the instrument add NULL or 1 value in a new column.
I can then take this to loop over some instrument checkboxes in Codeigniter, it just seems to make more sense to pull the data as I need it from the DB but am struggling to write the query.
teaching_instrument_list
- id
- instrument_name
teachers_instruments
- id
- teacher_id
- teacher_instrument_id
SELECT
a.instrument,
a.id
FROM
teaching_instrument_list a
LEFT JOIN
(
SELECT teachers_instruments.teacher_instrument_id
FROM teachers_instruments
WHERE teacher_id = 170
) b ON a.id = b.teacher_instrument_id
my query would look like this:
instrument name id value
--------------- -- -----
woodwinds 1 if the teacher has this instrument, set 1
brass 2 0
strings 3 1
One possible approach:
SELECT i.instrument_name, COUNT(ti.teacher_id) AS used_by
FROM teaching_instrument_list AS i
LEFT JOIN teachers_instruments AS ti
ON ti.teacher_instrument_id = i.id
GROUP BY ti.teacher_instrument_id
ORDER BY i.id;
Here's SQL Fiddle (tables' naming is a bit different).
Explanation: with LEFT JOIN on instrument_id we'll get as many teacher_id values for each instrument as teachers using it are - or just a single NULL value, if none uses it. The next step is to use GROUP BY and COUNT() to, well, group the result set by instruments and count their users (excluding NULL-valued rows).
If what you want is to show all the instruments and some flag showing whether or now a teacher uses it, you need another LEFT JOIN:
SELECT i.instrument_name, NOT ISNULL(teacher_id) AS in_use
FROM teaching_instrument_list AS i
LEFT JOIN teachers_instruments AS ti
ON ti.teacher_instrument_id = i.id
AND ti.teacher_id = :teacher_id;
Demo.
Well this can be achieved like this
SELECT
id,
instrument_name,
if(ti.teacher_instrument_id IS NULL,0,1) as `Value`
from teaching_instrument_list as til
LEFT JOIN teachers_instruments as ti
on ti.teacher_instrument_id = til.id
Add a column and check for teacher_instrument_id. If found set Value to 1 else 0.

Categories