Arithmetic operators with SELECT, LEFT JOIN and WHERE clause - php

I need help. I have the code below which works fine but its not achieving my objective. I want a column "account_title" with each of its calculated values by the side before the subtraction which should eventually give me the difference of the subtracted value. Thanks in anticipation.
SELECT
(
SELECT SUM(amount)
FROM mainaccount_a_2017
LEFT JOIN chart_of_account ON (chart_of_account.joint_account_numbers = mainaccount_a_2017.joint_account_number)
LEFT JOIN asset_liability_income_expenditure_tbl ON (asset_liability_income_expenditure_tbl.a_l_code = chart_of_account.account_type)
WHERE a_l_code = 'FA' AND dr_cr_action = 'DR'
)
-
(
SELECT SUM(amount)
FROM mainaccount_b_2017
LEFT JOIN chart_of_account ON (chart_of_account.joint_account_numbers = mainaccount_b_2017.joint_account_number)
LEFT JOIN asset_liability_income_expenditure_tbl ON (asset_liability_income_expenditure_tbl.a_l_code = chart_of_account.account_type)
WHERE a_l_code = 'FA' AND dr_cr_action = 'CR'
)

Change the subqueries to be grouped by account_title, and then join them.
SELECT debits.account_title, debits.total - credits.total AS net_reduction
FROM (
SELECT mainaccount_a_2017.account_title, SUM(amount) AS total
FROM mainaccount_a_2017
LEFT JOIN chart_of_account ON (chart_of_account.joint_account_numbers = mainaccount_a_2017.joint_account_number)
LEFT JOIN asset_liability_income_expenditure_tbl ON (asset_liability_income_expenditure_tbl.a_l_code = chart_of_account.account_type)
WHERE a_l_code = 'FA' AND dr_cr_action = 'DR'
GROUP BY mainaccount_a_2017.account_title
) AS debits
JOIN (
SELECT mainaccount_b_2017.account_title, SUM(amount) AS total
FROM mainaccount_b_2017
LEFT JOIN chart_of_account ON (chart_of_account.joint_account_numbers = mainaccount_b_2017.joint_account_number)
LEFT JOIN asset_liability_income_expenditure_tbl ON (asset_liability_income_expenditure_tbl.a_l_code = chart_of_account.account_type)
WHERE a_l_code = 'FA' AND dr_cr_action = 'CR'
GROUP BY mainaccount_b_2017.account_title
) AS credits ON debits.account_title = credits.account_title
DEMO

Related

simplify this SQL request

I have this sql request :
SELECT pl.*, l.loyer, l.charges, l.locataire_id, laire.nom, laire.prenom,
l.chambre_id, c.numero, c.etage, c.maison_id, m.titre_crm
FROM
(
SELECT spl.id, spl.location_id, spl.mois, spl.annee, spl.loyer_paye
from locations sl
LEFT JOIN
(
SELECT * FROM paiement_loyer
union
SELECT 9999, usl.id, (MONTH(NOW())-1), YEAR(NOW()), 0
FROM locations usl
WHERE usl.id not in (SELECT location_id FROM paiement_loyer) ||
(select count(*) FROM paiement_loyer
WHERE location_id = usl.id AND annee = YEAR(NOW())
AND mois=(MONTH(NOW())-1) ) = 0
) spl ON sl.id = spl.location_id
where sl.date_debut <= CURDATE() && CURDATE() <= sl.date_fin
) pl
JOIN locations l ON pl.location_id = l.id
JOIN locataires laire ON l.locataire_id = laire.id
JOIN chambres c ON l.chambre_id = c.id
JOIN maisons m ON c.maison_id = m.id
ORDER BY trim(upper(m.titre_crm)), c.numero, annee, mois
I would like to simplify it, do you have any idea please ?
An attempt at cleaning it up. Note that I think the first LEFT OUTER JOIN could probably be swapped to an INNER JOIN.
I have swapped the 2nd UNIONed query to 2 queries, and for those I have changed them to use LEFT OUTER JOINs which then check that there isn't a match
SELECT pl.id, pl.location_id, pl.mois, pl.annee, pl.loyer_paye,
l.loyer, l.charges, l.locataire_id, laire.nom, laire.prenom,
l.chambre_id, c.numero, c.etage, c.maison_id, m.titre_crm
FROM
(
SELECT spl.id, spl.location_id, spl.mois, spl.annee, spl.loyer_paye
FROM locations sl
LEFT OUTER JOIN
(
SELECT id, location_id, mois, annee, loyer_paye
FROM paiement_loyer
UNION
SELECT 9999, usl.id, (MONTH(NOW())-1), YEAR(NOW()), 0
FROM locations usl
LEFT OUTER JOIN paiement_loyer pl1
ON usl.id = pl1.location_id
WHERE pl1.location_id IS NULL
SELECT 9999, usl.id, (MONTH(NOW())-1), YEAR(NOW()), 0
FROM locations usl
LEFT OUTER JOIN paiement_loyer pl2
ON usl.id = pl1.location_id
AND pl2.annee = YEAR(NOW())
AND pl2.mois=(MONTH(NOW())-1)
WHERE pl2.location_id IS NULL
) spl ON sl.id = spl.location_id
WHERE CURDATE() BETWEEN sl.date_debut AND sl.date_fin
) pl
JOIN locations l ON pl.location_id = l.id
JOIN locataires laire ON l.locataire_id = laire.id
JOIN chambres c ON l.chambre_id = c.id
JOIN maisons m ON c.maison_id = m.id
ORDER BY TRIM(UPPER(m.titre_crm)), c.numero, pl.annee, pl.mois

Sub query return more than one field

I have a table structure like this
Table Structure
Here I want to select all the data from bus_routines table with bus details and avaliable_seat which is calculated from buses.number_of_seat - reserved_seats.number_of_reserved_seat - booking.number_of_seat even if the data is not present in booking table and reserved_seats table too where the bus_routines.sector_from=Ktm ,bus_routines.sector_to=Pkr and bus_routines.date=2015-12-15
Relation between them are :
buses and bus_routines --> one to many bus_routines and booking -->
one to many bus_routines and reserved_seats --> one to many
I have tried the following query
SELECT r.* , b.* ,
(
SELECT b.number_of_seat - sum(booking.number_of_seat)-sum(reserved_seats.number_of_reserved_seat)
FROM bus_routines AS r
INNER JOIN buses AS b
ON b.id = r.bus_id
INNER JOIN
(SELECT number_of_seat , bus_routine_id FROM booking GROUP BY booking.bus_routine_id) AS booking
ON booking.bus_routine_id = r.id
INNER JOIN (SELECT number_of_reserved_seat , routine_id FROM reserved_seats GROUP BY reserved_seats.routine_id) AS reserved_seats
ON r.id = reserved_seats.routine_id
WHERE
r.sector_from = "KTM" AND
r.sector_to = "PKR" AND
r.departure_date = "2015-12-15"
) AS avaliable_seat
FROM bus_routines AS r
INNER JOIN buses AS b
ON b.id = r.bus_id
WHERE
r.sector_from = "KTM" AND
r.sector_to = "PKR" AND
r.departure_date = "2015-12-15"
HAVING avaliable_seat > 0
I get the result what I want but the avaliable_seat is same for all the row
I have tried another query too but it give me the single result
SELECT r.* , b.* , b.number_of_seat - sum(booking.number_of_seat)-sum(reserved_seats.number_of_reserved_seat) AS available_seat
FROM bus_routines AS r
INNER JOIN buses AS b
ON b.id = r.bus_id
INNER JOIN
(SELECT number_of_seat , bus_routine_id FROM booking GROUP BY booking.bus_routine_id) AS booking
ON booking.bus_routine_id = r.id
INNER JOIN
(SELECT number_of_reserved_seat , routine_id FROM reserved_seats GROUP BY reserved_seats.routine_id) AS reserved_seats
ON r.id = reserved_seats.routine_id
WHERE
r.sector_from = "KTM" AND
r.sector_to = "PKR" AND
r.departure_date = "2015-12-15"
HAVING available_seat > 0
I also tried another query and it give me Subquery returns more than 1 row . The query is
SELECT r.* , b.* ,
b.number_of_seat - (SELECT sum(number_of_seat) FROM booking GROUP BY booking.bus_routine_id)
- (SELECT sum(number_of_reserved_seat) FROM reserved_seats GROUP BY reserved_seats.routine_id) AS available_seat
FROM bus_routines AS r
INNER JOIN buses AS b
ON b.id = r.bus_id
WHERE
r.sector_from = "KTM" AND
r.sector_to = "PKR" AND
r.departure_date = "2015-12-15"
HAVING available_seat > 0
One approach is to use correlated subqueries to get the reserved_seats and booked_seats for each bus_routine.
Let's assume that this query returns the rows you are wanting to return, it's just missing the available_seat column you want calculated:
SELECT r.*
, b.*
FROM bus_routines r
JOIN buses b
ON b.id = r.bus_id
WHERE r.sector_from = 'KTM'
AND r.sector_to = 'PKR'
AND r.departure_date = '2015-12-15'
To number of "reserved seats" for a given bus_routine, you can query the reserved_seats table, like this:
SELECT IFNULL(SUM(s.number_of_reserved_seat),0)
FROM reserved_seats s
WHERE s.routine_id = '649'
And the number of "booked seats" for a given bus_routine can be returned from the booking table, like this:
SELECT IFNULL(SUM(k.number_of_seat),0)
FROM booking k
WHERE k.bus_routine_id = '649'
We can incorporate the queries to get "reserved seats" and "booked seats" into the first query, as correlated subqueries. In place of the literal '649', with a reference the id from the bus_routine table.
SELECT r.*
, b.*
-- number of booked seats
, ( SELECT IFNULL(SUM(k.number_of_seat),0)
FROM booking k
WHERE k.bus_routine_id = r.id
) AS booked_seats
-- number of reserved seats
, ( SELECT IFNULL(SUM(s.number_of_reserved_seat),0)
FROM reserved_seats s
WHERE s.routine_id = r.id
) AS reserved_seats
-- calculate available seats as
-- (bus number_of_seat) - (booked_seats) - (reserved_seats)
, ( b.number_of_seat
- ( SELECT IFNULL(SUM(k.number_of_seat),0)
FROM booking k
WHERE k.bus_routine_id = r.id
)
- ( SELECT IFNULL(SUM(s.number_of_reserved_seat),0)
FROM reserved_seats s
WHERE s.routine_id = r.id
)
) AS avaliable_seat
FROM bus_routines r
JOIN buses b
ON b.id = r.bus_id
WHERE r.sector_from = 'KTM'
AND r.sector_to = 'PKR'
AND r.departure_date = '2015-12-15'
If there's no requirement to return the booked_seats and reserved_seats columns, those can be omitted from the query. The subqueries to get those values can just appear in the calculation of the available_seat column.
SQL Fiddle demonstration here: http://sqlfiddle.com/#!9/64eaa/7
Please try GROUP_CONCAT for return one column from multiple in subquery.
refer the links.
How to use GROUP_CONCAT in a CONCAT in MySQL
http://www.w3resource.com/mysql/aggregate-functions-and-grouping/aggregate-functions-and-grouping-group_concat.php

Counting number of statuses in group concat row

I've taken over a project that is a real mess so I've left with bad code structure that is forcing me to basically program in SQL. So changing the way of calculating this is for now not an option.
I have $sqlAdd variable that i need to populate in function and then concatenate that to main query to count number of lost tickets.
Main query looks like this:
$sql = "SELECT COUNT(*) as num_tickets, SUM(t.total_amount) as total_payin, SUM(t.total_payout) as total_payout
FROM t WHERE t.tickettime BETWEEN '$dateFrom' AND '$dateTo' AND t.bsid = $bsID
$sqlAdd";
So $sqlAdd is getting from another function
$sqlAdd = getSqlAdd();
And in that function i have this:
$sqlAdd = " AND 'WON' NOT IN (
SELECT GROUP_CONCAT(tr.ticketstatus)
FROM tr INNER JOIN m ON tr.ticketid = m.ticketid
WHERE tr.ticketid = t.ticketid GROUP BY m.ticket_groupid
)
AND 'PAYEDOUT' NOT IN (
SELECT GROUP_CONCAT(tr.ticketstatus)
FROM tr INNER JOIN m ON tr.ticketid = m.ticketid
WHERE tr.ticketid = t.ticketid GROUP BY m.ticket_groupid
)
AND 'CLOSED' NOT IN (
SELECT GROUP_CONCAT(tr.ticketstatus)
FROM tr INNER JOIN m ON tr.ticketid = m.ticketid
WHERE tr.ticketid = t.ticketid GROUP BY m.ticket_groupid
)
AND 'OPEN' NOT IN (
SELECT GROUP_CONCAT(tr.ticketstatus)
FROM tr INNER JOIN m ON tr.ticketid = m.ticketid
WHERE tr.ticketid = t.ticketid GROUP BY m.ticket_groupid
)";
GROUP_CONCAT(tr.ticketstatus) is getting me these rows when i execute it
CLOSED,CLOSED,CLOSED
PAYEDOUT,PAYEDOUT
CLOSED,CLOSED
WON,LOST
LOST,WON,WON,WON,WON,WON
CLOSED,CLOSED
LOST,LOST,WON
WON,WON,WON,LOST,LOST,WON,WON
LOST
I just want to count rows that have only LOST status in it. So the result should be 1. But i keep getting 7. It it counting every LOST status in results.
You would seem to want something like this:
SELECT COUNT(*) as num_tickets, SUM(t.total_amount) as total_payin,
SUM(t.total_payout) as total_payout
FROM t
WHERE t.tickettime BETWEEN '$dateFrom' AND
'$dateTo' AND t.bsid = $bsID AND
NOT EXISTS (SELECT 1
FROM tr NATURAL JOIN
m NATURAL JOIN
tg
WHERE tr.ticketid = t.ticketid AND
tr.ticketstatus IN ('WON', 'PAYEDOUT', 'CLOSED', 'OPEN')
);
Some notes:
GROUP_CONCAT() is not appropriate for this type of comparison. In SQL, you don't convert lists to strings and then do comparisons -- at least if you want performance.
You should avoid NATURAL JOIN. A small change to any of the tables can totally change the semantics of the query. In addition, it is unclear what the JOIN keys are. I would recommend USING instead.
You might want tr.ticketstatus NOT IN ('LOST') in the subquery.
So i've wrote very ugly query that is probably slow but its working i'm getting results that i need.
$sql = " AND ticket_groupid IN (
SELECT tg FROM t as tt
NATURAL JOIN tr NATURAL JOIN m
WHERE tt.tickettime BETWEEN '$dateFrom' AND '$dateTo' AND tt.bsid = $bsid
AND 'LOST' IN (
SELECT GROUP_CONCAT(tr.ticketstatus)
FROM tr NATURAL JOIN m as mm
WHERE mm.ticket_groupid = m.ticket_groupid
)
GROUP BY mm.ticket_groupid )"

Double Count Select return wrong result

Hello I am using the following query to display the count of the rows where id is the same number from first table, I have 2 more tables. If I leave only one count evertything is working fine but with double count select I am getting the same result which is wrong:
'SELECT c.*, count(s.userID) as count_consulta, count(a.userID) as count_asesoria
FROM users as c
LEFT JOIN consulta AS s ON s.userID = c.userID
LEFT JOIN asesoria AS a ON a.userID = c.userID
GROUP BY c.userID DESC'
with this I am getting:
count_consulta = 15
count_asesoria = 15
where it should be
count_consulta = 3
count_asesoria = 5
any help will be welcome. Thanks!
With the statement "any help will be welcome" I throw this out there to see if it does what you mean.
$sql="select *,
( select count( distinct s.`userID` ) from `consulta` ) as 'count_consulta',
( select count( distinct a.`userID` ) from `asesoria` ) as 'count_asesoria'
from `users` c
left outer join `consulta` s on s.`userID`=c.`userID`
left outer join `asesoria` a on a.`userID`=c.`userID`
group by c.`userID` desc;";

Add a filter to a large mysql query

I have this large query, and I just need to filter out any results where the tbl_dealinterest.Active = 'n'. There sometimes isn't an entry in that table for the product, and sometimes it might there might be and entry and set to y.
Here is the large ugly query:
SELECT tbl_product.id, tbl_productspecification.id AS specificationId,
tbl_product.ProductId, tbl_seller.CompanyName, tbl_product.ProductName, tbl_product.Description, mst_Categories.id AS 'Category',
tbl_productspecification.RetailPrice, tbl_productspecification.SalePrice,
tbl_product.image, tbl_productspecification.Discount, tbl_product.EndTime, tbl_product.Seller_Id, tbl_dealinterest.Active AS thumbsActive
FROM tbl_product
LEFT OUTER JOIN tbl_seller ON tbl_seller.SelId = tbl_product.Seller_Id
LEFT OUTER JOIN mst_Categories ON (mst_Categories.id = tbl_product.Category OR mst_Categories.id = tbl_product.SubCategory)
LEFT OUTER JOIN tbl_productspecification ON tbl_productspecification.ProductId = tbl_product.ProductId
LEFT OUTER JOIN mst_image ON mst_image.Product = tbl_product.ProductId
LEFT OUTER JOIN tbl_dealinterest ON tbl_dealinterest.ProductId = tbl_product.ProductId AND tbl_dealinterest.BuyerId = '$token'
WHERE tbl_product.Active='y'
AND tbl_product.StartTime <= '".date("Y-m-d H:i:s")."'
AND tbl_product.EndTime > '".date("Y-m-d")." 06:00:00'
".$subquery."
GROUP BY tbl_productspecification.ProductId";
Thanks for any suggestions.
SELECT ...
WHERE tbl_product.Active='y'
AND (tbl_dealinterest.Active <> 'n' OR tbl_dealinterest.Active IS NULL)
...
LEFT OUTER JOIN tbl_dealinterest ON (tbl_dealinterest.ProductId = tbl_product.ProductId
AND tbl_dealinterest.BuyerId = '$token'
AND tbl_dealinterest.Active<>'n')

Categories