Im trying to combine tables with LEFT JOIN and SUBSTR LOCATE. One of the tables (ClientService) has a column named description and the record i need is between " "
for example: This is a test "Example". I need Example to compare with my other table (HostingAccount)
This is the query i have.
SELECT
CS.ClientServiceID,
S.ServiceID,
CS.InvoicePeriod,
CS.Period,
S.Price,
S.ServiceCategoryID,
IF(LENGTH(CS.Description) > 0, CS.Description, S.Description) AS Description,
CS.Discount,
DATE_FORMAT(CS.StartDate, "%d-%m-%Y") AS StartDate,
'.($Timestamp === TRUE ? 'UNIX_TIMESTAMP(CS.PayedUntill)' : 'DATE_FORMAT(IFNULL(CS.PayedUntill, DATE_ADD(CS.StartDate, INTERVAL 1 YEAR)), "%d-%m-%Y")').' AS PayedUntill,
DATEDIFF(NOW(), CS.PayedUntill) AS PayedUntillDifference,
CS.ReferenceID,
CS.External,
CS.Redirect,
CS.RedirectType,
CS.Active,
H.HostingID,
H.ServerIP,
H.Username
FROM ClientService AS CS
JOIN Client AS C
ON C.ClientID = CS.ClientID
JOIN Service AS S
ON S.ServiceID = CS.ServiceID
LEFT JOIN Hosting AS H
ON H.HostingID = CS.ReferenceID
AND H.ClientID = C.ClientID
---> LEFT JOIN HostingAccount AS HA
ON HA. <----
WHERE CS.ClientServiceID = :CSID
AND C.ClientID = :CID
AND CS.Active IN (1,5,6,9)
I've marked the LEFT JOIN HostingAccount with ---> <--- and it has the Example description in it without the " "
This query i've tested and it gives me the record without the " " from table ClientService
SELECT SUBSTR(Description, LOCATE('"',Description)+1,
(CHAR_LENGTH(Description) - LOCATE('"',REVERSE(Description)) -
LOCATE('"',Description))) from ClientService
Question:
How can i combine the SUBSTR query with the LEFT JOIN HostingAccount AS HA
ON HA.description (Without the delimiter) = CS.description (Between the delimiter)
I have not tested the following and I'm not 100% sure I followed the question but I think you mean something like this?
<?php
$sql='SELECT
CS.`ClientServiceID`,
S.`ServiceID`,
CS.`InvoicePeriod`,
CS.`Period`,
S.`Price`,
S.`ServiceCategoryID`,
IF( LENGTH( CS.`Description` ) > 0, CS.`Description`, S.`Description`) AS "Description",
CS.`Discount`,
DATE_FORMAT(CS.`StartDate`, "%d-%m-%Y") AS "StartDate",
' .( $Timestamp === TRUE ? 'UNIX_TIMESTAMP( CS.`PayedUntill` )' : 'DATE_FORMAT(IFNULL(CS.`PayedUntill`, DATE_ADD(CS.`StartDate`, INTERVAL 1 YEAR)), "%d-%m-%Y")' ) . ' AS "PayedUntill",
DATEDIFF(NOW(), CS.`PayedUntill`) AS "PayedUntillDifference",
CS.`ReferenceID`,
CS.`External`,
CS.`Redirect`,
CS.`RedirectType`,
CS.`Active`,
H.`HostingID`,
H.`ServerIP`,
H.`Username`
FROM `ClientService` CS
JOIN `Client` C ON C.ClientID = CS.ClientID
JOIN `Service` S ON S.ServiceID = CS.ServiceID
LEFT JOIN `Hosting` H ON H.HostingID = CS.ReferenceID AND H.ClientID = C.ClientID
LEFT JOIN `HostingAccount` HA ON HA.`description`=(
SELECT SUBSTR(`Description`, LOCATE( \'"\', `Description` )+1,
( CHAR_LENGTH( `Description`) - LOCATE(\'"\',REVERSE(`Description`) ) -
LOCATE(\'"\',Description)))
from `ClientService`
)
WHERE CS.`ClientServiceID` = :CSID
AND C.`ClientID` = :CID
AND CS.`Active` IN (1,5,6,9)';
?>
Related
I am trying to build a query that retrieves all reservations within a date timeframe and joins a payment table to calculate total payments, and few other things. The query seems to work just fine except it is leaving out reservations that have no payments. Any help would be greatly appreciated.
SELECT
reservations.reservation_id ,
properties. NAME ,
properties.address1 AS prop_address ,
reservations.last_name ,
reservations.arrival_date ,
reservations.departure_date ,
reservations.date_created ,
reservations.contract_filename ,
reservations.contract_signed ,
reservation_payments.date_of_payment ,
(
SUM(
reservations.cleaning_fee + reservations.processing_fee + reservations.pool_heat_fee + reservations.special_fees + reservations.hoa_fees + reservations.rental_fee + reservations.taxes
) - COALESCE(
SUM(
reservation_payments.amount_paid
) ,
0
)
) AS sub_total ,
COALESCE(
SUM(
reservation_payments.amount_paid
) ,
0
) AS total_paid_to_date ,
reservations.balance_due_date ,
(
SELECT
GROUP_CONCAT(
DISTINCT user_meta.first_name
ORDER BY
associated_sales_staff.display_order ASC SEPARATOR ", "
)
FROM
associated_sales_staff
JOIN user_meta ON user_meta.user_id = associated_sales_staff.user_id
WHERE
(
associated_sales_staff.reservation_id = reservations.reservation_id
)
) AS sales_agents
FROM
reservations
JOIN properties ON properties.prop_id = reservations.property_id
JOIN reservation_payments ON reservation_payments.reservation_id = reservations.reservation_id
WHERE
properties.active_for_cleaning_schedule = 1
AND reservations.arrival_date >= "2017-05-15"
AND reservations.departure_date <= "2017-05-30"
GROUP BY
reservations.reservation_id
HAVING
(sub_total >= 1)
ORDER BY
total_paid_to_date ASC
I found the problem was with the JOIN of reservation_payments table.
I updated From:
JOIN reservation_payments ON reservation_payments.reservation_id = reservations.reservation_id
To:
LEFT JOIN reservation_payments ON reservations.reservation_id = reservation_payments.reservation_id
I need to add a field in one of our query. I'm nt a PHP programmer buy I can get my way around a little. The query is:
if (_QUERYSTRING_) {
switch ($intMode) {
case -1:
$result = mysqli_query($mysql,"
SELECT orders.id,
orders_addresses.strlastname,
orders_addresses.strfirstname,
orders_addresses.intprovince,
9 AS intmode,
Date(orders.dtimeorder) AS datepayment,
orders_costs.dbltotal AS dblamount,
orders_notes.strcod AS strtxn,
0 AS dblfee,
shipping_postalservices.strtracking"._LANG_." as strtrackingurl,
'À recevoir' AS strmode,
NULL AS strvendor
FROM orders
JOIN orders_costs
ON orders_costs.id = orders.id
JOIN orders_addresses
ON orders_addresses.id = orders.id
JOIN orders_notes
ON orders_notes.id = orders.id
JOIN shipping_postalservices
ON shipping_postalservices.id = orders_costs.intpostalservice
WHERE date(orders.dtimeorder) BETWEEN '".date("Y-m-d",$timeStart)."' AND '".date("Y-m-d",$timeEnd)."'
AND orders.boolshipped = 1
AND orders.boolcanceled = 0
AND orders_costs.boolcod = 1
AND orders_costs.dbltotal > 0
AND NOT EXISTS
(
SELECT *
FROM orders_payments
WHERE orders_payments.intorder = orders.id
AND orders_payments.intmode = 9
AND orders_payments.dblamount > 0)
GROUP BY orders.id
ORDER BY orders.dtimeorder,
orders.id");
break;
default:
$result = mysqli_query($mysql,"
SELECT orders.id,
orders_addresses.strlastname,
orders_addresses.strfirstname,
orders_addresses.intprovince,
orders_payments.intmode,
Date(orders_payments.dtimepayment) AS datepayment,
orders_payments.dblamount,
orders_payments.strtxn,
orders_payments.dblfee,
shipping_postalservices.strtracking"._LANG_." as strtrackingurl,
payments.strname"._LANG_." AS strmode,
payments.strvendor
FROM orders_payments
JOIN orders
ON orders.id = orders_payments.intorder
JOIN orders_costs
ON orders_costs.id = orders.id
JOIN orders_addresses
ON orders_addresses.id = orders.id
JOIN shipping_postalservices
ON shipping_postalservices.id = orders_costs.intpostalservice
LEFT JOIN payments
ON payments.id = orders_payments.intmode
WHERE date(orders_payments.dtimepayment) BETWEEN '".date("Y-m-d",$timeStart)."' AND '".date("Y-m-d",$timeEnd)."'".(!empty($intMode) ? "
AND orders_payments.intmode = '".$intMode."'" : NULL)."
GROUP BY orders.id,
orders_payments.intpayment
ORDER BY orders_payments.dtimepayment,
orders.id");
break;
}
The field that needs to be added is orders_addresses.intProvince so it can be displayed in the results. I tried to understand a little but I guess it's a little more complicated than I thought. It does display the province, which are numbers. My question would be, how do I "translate" those numbers by the actual names so it displays "Ontario" instead of 9? The name of the provinces are in another table called Province.
You will need to add another JOIN:
JOIN Province ON orders_addresses.intprovince = Province.x
And in the SELECT part, replace orders_addresses.intprovince by Province.y
where
x = column in table Province that holds the province id
y = column in table Province that holds the province name
Although the query returns the result but the group by Month returns result alphabetically like April,August,June ... but it should return result Chronologically like Jan ,Feb,....
SELECT Concat(Monthname(a.fdate), '-', Year(a.fdate)) AS Month,
s.new_state AS State,
d.new_dist AS District,
b.ifbook AS Book,
Sum(a.amt) AS Amount
FROM str a
JOIN sc b
ON b.scd = a.isc
JOIN USER c
ON a.ed = c.str
JOIN state_mapping s
ON b.state = s.org_state
JOIN dist_mapping d
ON b.dist = d.org_dist
WHERE Trim(b.ifbook) <> ''
AND b.ifbook IS NOT NULL
AND b.ifbook NOT LIKE '%TR%'
AND Trim(d.new_dist) <> ''
AND d.new_dist IS NOT NULL
GROUP BY b.ifbank,
d.new_dist,
s.new_state,
month
How can I modify the query to achieve the same?
Without knowing anything about your model I could suggest you to give this a shot:
select
concat(monthname(a.fdate),'-',year(a.fdate)) Month,
s.new_state State,
d.new_dist District,
b.ifbook Book,
sum(a.amt) Amount
from str a
JOIN sc b on b.scd = a.isc
JOIN user c on a.ed = c.str
JOIN state_mapping s on b.state = s.org_state
JOIN dist_mapping d on b.dist = d.org_dist
where TRIM(b.ifbook) <> '' and b.ifbook IS NOT NULL and b.ifbook not like '%TR%'
and TRIM(d.new_dist) <> '' and d.new_dist IS NOT NULL
group by b.ifbank, d.new_dist, s.new_state, Month
order by year(a.fdate), month(a.fdate)
I am using doctrine in my symfony2 project.
I have a table Event and a table Photo. One event can have one or more photos, and a photo is related to one event.
Here is one of my dql queries :
$dql = "
SELECT e, (e.views * 0.1) + (e.likes * 0.9) as ratingEvent
FROM WevseenMainBundle:Event e
INNER JOIN e.photos p
INNER JOIN e.firstPhoto fp
WHERE fp.date BETWEEN :dateA AND :dateB
AND p.lat BETWEEN :latA AND :latB
AND ( p.lng > :lngA AND p.lng < :lngB )
AND e.status = 'open'
GROUP BY e
HAVING COUNT(p.id) >= :minCountPhotos
ORDER BY ratingEvent DESC
";
$query = $em->createQuery($dql)
->setParameters($parameters)
->setFirstResult($firstEntry) // 0
->setMaxResults($numberOf); // 10
$paginatorEvents = new Paginator($query, true);
With something like 11500 events and 160 000 photos, the query is very slow (more than 10 seconds), it is coming from the
GROUP BY e
HAVING COUNT(p.id) >= :minCountPhotos
Without this, it's fast.
I checked the sf2 profiler and it says that :
SELECT count(DISTINCT e0_.id) AS sclr0 FROM Event e0_ INNER JOIN Photo p1_ ON e0_.id = p1_.event_id INNER JOIN Photo p2_ ON e0_.firstPhoto_id = p2_.id WHERE p2_.date BETWEEN ? AND ? AND p1_.lat BETWEEN ? AND ? AND (p1_.lng > ? AND p1_.lng < ?) AND e0_.status = 'open' GROUP BY e0_.id, e0_.name, e0_.description, e0_.nb_photos, e0_.views, e0_.viewsEventPhotos, e0_.votes, e0_.rating, e0_.likes, e0_.up, e0_.down, e0_.status, e0_.end, e0_.time, e0_.averageTimeEvent, e0_.averageTimePhotos, e0_.averageTimeEventAndPhotos, e0_.needInstagramUpdate, e0_.origin, e0_.featured, e0_.firstPhoto_id HAVING COUNT(p1_.id) >= ?
Parameters: [Object(DateTime), Object(DateTime), '-42.93442389074508', '73.48078267112892', '-180', '180', '2']
Time: 2029.33 ms
SELECT DISTINCT e0_.id AS id0, e0_.views * 1 + e0_.likes * 0 AS sclr1 FROM Event e0_
INNER JOIN Photo p1_ ON e0_.id = p1_.event_id INNER JOIN Photo p2_ ON e0_.firstPhoto_id = p2_.id WHERE p2_.date BETWEEN ? AND ? AND p1_.lat BETWEEN ? AND ? AND (p1_.lng > ? AND p1_.lng < ?) AND e0_.status = 'open' GROUP BY e0_.id, e0_.name, e0_.description, e0_.nb_photos, e0_.views, e0_.viewsEventPhotos, e0_.votes, e0_.rating, e0_.likes, e0_.up, e0_.down, e0_.status, e0_.end, e0_.time, e0_.averageTimeEvent, e0_.averageTimePhotos, e0_.averageTimeEventAndPhotos, e0_.needInstagramUpdate, e0_.origin, e0_.featured, e0_.firstPhoto_id HAVING COUNT(p1_.id) >= ? ORDER BY sclr1 DESC LIMIT 10 OFFSET 0
Time: 6179.01 ms
which are the two queries that takes time.
How can I improve this ?
UPDATE, SOLUTION:
changed
GROUP BY e
with
GROUP BY e.id
Your request is executed only when you iterate on the paginator.
You should copy the translated SQL request and profile it outside of Doctrine, chances are it will take 8 seconds to execute. And chances are it will be much faster once you add some wisely chosen indexes to your tables.
I'm trying to build what should be (in my mind anyway) a simply SQL query to understand what clients have been invoiced each financial year. The output might look like this:
{clientName (Client A)} - {2010/2011 Value} - {2011/2012 Value} - {2012/2013 Value}
What I've been able to achieve is an output that looks like this:
{clientName (Client A)} - {2010/2011 Value}
{clientName (Client A)} - {2011/2012 Value}
{clientName (Client A)} - {2012/2013 Value}
{clientName (Client B)} - {2010/2011 Value}
And so on…
Now, I know this is not correct but the query I'm working with looks like this:
$query = "SELECT i.invoiceValue, fy.year, c.clientName, c.clientID FROM cms_invoices i
LEFT JOIN cms_financialYear fy ON fy.yearID = i.yearID
LEFT JOIN cms_projects p ON p.projectID = i.projectID
LEFT JOIN cms_clients c ON c.clientID = p.clientID
ORDER BY fy.year, c.clientName";
$result = mysql_query($query) or die(mysql_error());
while($row = mysql_fetch_array($result)) {
echo $row['year'] . " - ";
echo $row['clientName'] . " - $";
echo number_format($row[invoiceValue], 2, '.', ',') . "";
echo "<br>";
I'd be much appreciated if I could get some sort of a steer on this. I've tried for hours but alas, no luck.
Thanks,
#rrfive
You could try something like this:
SELECT c.clientID
, c.clientName
, SUM(IF(fy.year=2010,i.invoiceValue,0)) AS fy_2010
, SUM(IF(fy.year=2011,i.invoiceValue,0)) AS fy_2011
, SUM(IF(fy.year=2012,i.invoiceValue,0)) AS fy_2012
FROM cms_invoices i
LEFT
JOIN cms_financialYear fy ON fy.yearID = i.yearID
LEFT
JOIN cms_projects p ON p.projectID = i.projectID
LEFT
JOIN cms_clients c ON c.clientID = p.clientID
GROUP BY c.clientID, c.clientName
ORDER BY c.clientID, c.clientName
The "trick" is to use an IF function (or a more ANSI portable CASE expression), to determine if a row applies to a given fiscal year. If it does, then return the invoice value, otherwise, return a 0.
Wrap those expressions in a SUM aggregate function, and do the GROUP BY on the client.
If you want to guard against returning a NULL value, then you can wrap those SUM expressions in an IFNULL( ... ,0)