I have to write a query to retrieve data from a table, using the selected date and selected category. I have written a query and it does not give correct data as expected. It should query only rows with maximum actiondate, if the action column has the value 'AD'.
INSERT INTO goldstockvaluation SELECT sh.stockid, sh.description, sh.branch, sh.grossweight, sh.pureweight, sh.purity, sh.goldcarat, sh.mcpergram, sh.goldpergram, sh.fixgold, CURDATE( )
FROM stock_history sh
JOIN (
SELECT stockid, branch,ACTION , MAX( actiondate ) AS MaxDateTime
FROM stock_history
GROUP BY stockid,branch,ACTION
)groupedsh ON sh.stockid = groupedsh.stockid
AND sh.actiondate = groupedsh.MaxDateTime
AND sh.branch = groupedsh.branch
AND sh.action = groupedsh.action
AND sh.branch = '8'
AND sh.categoryid = 'G'
AND sh.action = 'AD'
AND sh.actiondate <= '2016-03-28 23:59:59'
This is to query out the rows that have action as 'AD' and have the max(actiondate).
To query with max(action_date), you need to use sub query, e.g.:
select field1, field2
from table
where
sh.action = 'AD'
and sh.actiondate = (
select max(sh.actiondate)
from table
where sh.action = 'AD'
);
Related
I have an SQL Query that used to have inclusive <> '1' as a clause but I had to remove it to ensure I pick up all the data but I still need to count the value of the inclusive field in the SUM
Is it possible to make the SUM(customer_cost) as customer_total not include rows where inclusive <> '1'
$callChargesSql = "SELECT
customer,
source,
source_name,
calltype,
SUM(customer_cost) as customer_total,
SUM(cost) as cost,
SUM(recording_cost) as recording_cost,
SUM(recording_customer) as recording_customer
FROM
billing_calldata
WHERE
(
customer = '".db_string($result["sequence"])."' OR
customer IN
(
SELECT
sequence
FROM
customer
WHERE
resellerid = '".db_string($result["sequence"])."'
)
) AND
(
(
MONTH(timestamp) = '".db_string($calls["month"])."' AND
YEAR(timestamp) = '".db_string($calls["year"])."'
) OR
status = 'y'
)
GROUP BY customer, source, calltype
ORDER BY customer, timestamp ASC;";
In MySQL you can use IF statement within SUM operator like:
SUM(IF(inclusive = '1',customer_cost, 0)) as customer_total
Below simplified example:
select
customer_id,
sum(customer_cost) as total_customer_cost,
sum(if(inclusive=1, customer_cost, 0)) as inclusive_customer_cost
from billing_calldata
group by customer_id
;
Here you can test it: SQLize.online
In my test you can
You can use something like this: SUM(case when inclusive = '1' then customer_cost else 0 end) as customer_total
In your example query:
$callChargesSql = "SELECT
customer,
source,
source_name,
calltype,
SUM(case when inclusive = '1' then customer_cost else 0 end) as customer_total,
SUM(cost) as cost,
SUM(recording_cost) as recording_cost,
SUM(recording_customer) as recording_customer
FROM
billing_calldata
WHERE
(
customer = '".db_string($result["sequence"])."' OR
customer IN
(
SELECT
sequence
FROM
customer
WHERE
resellerid = '".db_string($result["sequence"])."'
)
) AND
(
(
MONTH(timestamp) = '".db_string($calls["month"])."' AND
YEAR(timestamp) = '".db_string($calls["year"])."'
) OR
status = 'y'
)
GROUP BY customer, source, calltype
ORDER BY customer, timestamp ASC;";
I'm writing a Logging System for Items where i track the Quantity and Type of various Objects.
And i need to write a Insert Query where it only imports if the Quantity (qty) has changed since the last time.
This is the Query to get the last inserted Quantity:
SELECT qty FROM `qty` WHERE object='object_name' AND type='type' ORDER BY UNIX_TIMESTAMP(timestamp) DESC LIMIT 1
But now how do i say: Import only if quantity given by Programm is not the Quantity given by the Query above
Edit:
Here is the Normal insert:
INSERT INTO `qty` (qty, object, type) VALUES ("quantity", "object_name", "type")
Edit:
I got it working now!
thanks everybody for the response! you guys are awesome :)
INSERT INTO qty (qty, object, type)
SELECT * FROM (SELECT 'qty-value', 'object-value', 'type-value') AS tmp
WHERE NOT EXISTS (
SELECT * FROM (SELECT qty FROM `qty` WHERE object = 'object-value' AND type = 'type-value' ORDER BY UNIX_TIMESTAMP( timestamp ) DESC LIMIT 1) as lastQTY WHERE qty = "qty-value"
) LIMIT 1;
If you want to insert new values, try matching the new values to the old values. If there is a match, then filter out the rows. I think the key is using insert . . . select rather than insert . . . values.
The following gives the idea:
INSERT INTO qty(qty, object, type)
select #quantity, #object_name", #type
from (select #quantity as quantity, #object_name as object_name, #type as type
) as newrow left outer join
(SELECT qty.*
FROM qty
WHERE object = #object_name AND type = #type
ORDER BY UNIX_TIMESTAMP(timestamp) DESC
LIMIT 1
) oldrow
on newrow.quantity = oldrow.quantity and
newrow.object_name = oldrow.object_name and
newrow.type = oldrow.type
where oldrow is null;
Think this would do it.
This takes your input values, joins that against a sub query to get the latest timestamp for the object and type, and then joins that against the qty table to get the value of the column qty for the latest timestamp and that the qty is the same as the new qty.
The WHERE clause is then checking that the value of the latest qty is NULL (ie, assuming the qty can not legitimatly be NULL there is no record found )
INSERT INTO `qty_test` (qty, object, type)
SELECT a.qty, a.object, a.type
FROM
(
SELECT 1 AS qty, 1 AS object, 1 AS type
) a
LEFT OUTER JOIN
(
SELECT object, type, MAX(timestamp) AS max_timestamp
FROM qty_test
GROUP BY object, type
) b
ON a.object = b.object
AND a.type = b.type
LEFT OUTER JOIN qty_test c
ON a.object = c.object
AND a.type = c.type
AND a.qty = c.qty
AND b.max_timestamp = c.timestamp
WHERE c.qty IS NULL
I have a table CONTACT with a field opt_out.
The field opt_out may have values 'Y', 'N' and NULL.
I have a table CONTACT_AUDIT with fields
date
contact_id
field_name
value_before
value_after
When I add a new contact, a new line is added in the CONTACT table, nothing the CONTACT_AUDIT table.
When I edit a contact, for example if I change the opt_out field value from NULL to 'Y', the opt_out field value in CONTACT table is changed and a new line is added to CONTACT_AUDIT table with values
date=NOW()
contact_id=<my contact's id>
field_name='opt_out'
value_before=NULL
value_after='Y'
I need to know the contacts who had opt_out='Y' at a given date.
I tried this :
SELECT count(*) AS nb
FROM contacts c
WHERE
( -- contact is optout now and has never been modified before
c.optout = 'Y'
AND c.id NOT IN (SELECT DISTINCT contact_id FROM contacts_audit WHERE field_name = 'optout')
)
OR ( -- we consider contacts where the last row before date in contacts_audit is optout = 'Y'
c.id IN (
SELECT ca.contact_id
FROM contacts_audit ca
WHERE date_created BETWEEN '2014-07-24' AND DATE_ADD( '2014-07-24', INTERVAL 1 DAY )
AND field_name = 'optout'
ORDER BY date_created
LIMIT 1
)
)
But mysql does not support LIMIT in subquery.
So I tried with HAVING :
SELECT count(*) AS nb
FROM contacts c
WHERE
( -- contact is optout now and has never been modified before
c.optout = 'Y'
AND c.id NOT IN (SELECT DISTINCT contact_id FROM contacts_audit WHERE field_name = 'optout')
)
OR ( -- we consider contacts where the last row before date in contacts_audit is optout = 'Y'
c.id IN (
SELECT ca.contact_id
FROM contacts_audit ca
WHERE date_created BETWEEN '2014-07-24' AND DATE_ADD( '2014-07-24', INTERVAL 1 DAY )
AND field_name = 'optout'
HAVING MAX(date_created)
)
)
The query runs, but now, I don't know how to know if the value corresponding to the subquery value is 'Y' or 'N'. If I add a WHERE clause to check only for 'Y' values, 'N' values will be filtred and I will not be able to know if the last value at date was 'Y' or 'N'...
Thank you for your help
If i understand your problem correctly you may want to use a union. I dont have mysql to test it right now but the code could be something like this. tell me if this helped
select c.id, c.optout
where c.optout = 'Y'
AND c.id NOT IN (SELECT DISTINCT contact_id FROM contacts_audit WHERE field_name = 'optout')
UNION
select c.id, c.optout where c.id IN (
SELECT ca.contact_id
FROM contacts_audit ca
WHERE date_created BETWEEN '2014-07-24' AND DATE_ADD( '2014-07-24', INTERVAL 1 DAY )
AND field_name = 'optout'
HAVING MAX(date_created)
)
I hope this is the appropriate forum to ask for assistance. I have an SQL Query (MySQL) that is not returning the correct records in a Date Range (between two dates). I am happy to answer questions in relation to the query, however if anyone can make suggestions or correct the SQL Query that would be an excellent learning exercise. Thank you.
$raw_query = sprintf("SELECT
swtickets.ticketid AS `Ticket ID`,
swtickettimetracks.tickettimetrackid AS `Track ID`,
swtickets.ticketmaskid AS `TicketMASK`,
(
SELECT
swcustomfieldvalues.fieldvalue
FROM
swcustomfieldvalues,
swcustomfields
WHERE
swcustomfieldvalues.customfieldid = swcustomfields.customfieldid
AND swtickets.ticketid = swcustomfieldvalues.typeid
AND swcustomfields.title = 'Member Company'
ORDER BY
swcustomfieldvalues.customfieldvalueid DESC
LIMIT 1
) AS MemberCompany,
(
SELECT
swcustomfieldvalues.fieldvalue
FROM
swcustomfieldvalues,
swcustomfields
WHERE
swcustomfieldvalues.customfieldid = swcustomfields.customfieldid
AND swtickets.ticketid = swcustomfieldvalues.typeid
AND swcustomfields.title = 'Member Name'
ORDER BY
swcustomfieldvalues.customfieldvalueid DESC
LIMIT 1
) AS MemberName,
(
SELECT
swcustomfieldvalues.fieldvalue
FROM
swcustomfieldvalues,
swcustomfields
WHERE
swcustomfieldvalues.customfieldid = swcustomfields.customfieldid
AND swtickets.ticketid = swcustomfieldvalues.typeid
AND swcustomfields.title = 'Chargeable'
AND
swcustomfieldvalues.fieldvalue = '40'
ORDER BY
swcustomfieldvalues.customfieldvalueid ASC
LIMIT 1
) AS `Chg`,
swtickets.`subject` AS `Subject`,
swtickets.departmenttitle AS Category,
FROM_UNIXTIME(
swtickettimetracks.workdateline
) AS `workDateline`,
FROM_UNIXTIME(
swtickettimetracks.dateline
) AS `dateline`,
swtickettimetracks.timespent AS `Time Spent`,
swtickets.timeworked AS `Time Worked`
FROM
swtickets
INNER JOIN swusers ON swtickets.userid = swusers.userid
INNER JOIN swuserorganizations ON swuserorganizations.userorganizationid = swusers.userorganizationid
INNER JOIN swtickettimetracks ON swtickettimetracks.ticketid = swtickets.ticketid
WHERE
swuserorganizations.organizationname = '%s'
AND (
swtickets.ticketstatustitle = 'Closed'
OR swtickets.ticketstatustitle = 'Completed'
)
AND FROM_UNIXTIME(`workDateline`) >= '%s' AND FROM_UNIXTIME(`workDateline`) <= '%s'
ORDER BY `Ticket ID`,`Track ID`",
$userOrganization,
$startDate,
$endDate
);
As I mentioned, the Query works - however it does not return the records correctly between the two dates.
However, IF I run this simple query against the database :
SELECT swtickettimetracks.tickettimetrackid,
swtickettimetracks.ticketid,
swtickettimetracks.dateline,
swtickettimetracks.timespent,
swtickettimetracks.timebillable,
FROM_UNIXTIME(swtickettimetracks.workdateline)
FROM swtickettimetracks
WHERE FROM_UNIXTIME(swtickettimetracks.workdateline) >= '2013-04-16' AND FROM_UNIXTIME(swtickettimetracks.workdateline) <= '2013-04-18'
I get the correct date range returned. Help? Thank you in anticipation.
Edward.
Unless you are overthinking it, it's all in your different query WHERE clauses...
Your complex query returning the wrong results has
(join conditions between other tables)
AND swuserorganizations.organizationname = '%s'
AND ( swtickets.ticketstatustitle = 'Closed'
OR swtickets.ticketstatustitle = 'Completed' )
AND FROM_UNIXTIME(`workDateline`) >= '%s'
AND FROM_UNIXTIME(`workDateline`) <= '%s'
Your Other query has
FROM swtickettimetracks
WHERE FROM_UNIXTIME(swtickettimetracks.workdateline) >= '2013-04-16'
AND FROM_UNIXTIME(swtickettimetracks.workdateline) <= '2013-04-18'
So I would consider a few things. The first where has
FROM_UNIXTIME >= '%s' and FROM_UNIXTIME <= '%s'
Are you sure the '%s' values are properly formatted to match the '2013-04-16' and '2013-04-18' format sample?
But more importantly, your first query is using the same date range (if correct), but is also only getting those for specific organization name AND (Closed or Completed) records. So, if the second query is returning 100 records, but the main query only 70, then are the other 30 some status other than closed/completed, or a different organization? In addition, if the join tables don't have matching IDs that would prevent those with invalid IDs from being returned. The only way to confirm that is to change to LEFT-JOIN syntax on those tables and see the results.
Update a single column over multiple rows depending on the data from the same table.
update table1 set status=newtime
from (
select
case
when TIME_FORMAT( TIMEDIFF( ADDTIME( time_val, '120:00:00' ), NOW() ), '%Hh %im %ss')<0 then '4'
else '0'
end as newtime,
id as new_id
FROM table1
where id2='2'
and status='0'
)
where id=new_id
This is my query. Thanks in advance.
Edit:
This is an alternate query to achieve this. But it also gives me an error
update table1 set status=
(select
case when timeleft<0 then '4' else '0' end as something,
new_id
from
(
select
TIME_FORMAT( TIMEDIFF( ADDTIME( time_val, '120:00:00' ), NOW() ), '%Hh %im %ss') as newtime,
id as new_id
FROM
table1
where id2='2' and
status='0'
)
}
where id=new_id
"#1248 - Every derived table must have its own alias".
I cannot use alias as I am fetching two columns from the query. Any help would be great.
UPDATE statements have no FROM clause in MySQL syntax. However, you can JOIN table against the subquery.
UPDATE
table1 t1
JOIN (
select
case
when TIME_FORMAT( TIMEDIFF( ADDTIME( time_val, '120:00:00' ), NOW() ), '%Hh %im %ss')<0 then '4'
else '0'
end as newtime,
id as new_id
FROM table1
WHERE id2='2' AND status='0'
) tsub ON t1.id = tsub.new_id
SET status = tsub.newtime
It looks to me like you don't need to do any subquerying or joining at all. This should do what you want:
UPDATE table1
SET status = CASE WHEN TIME_FORMAT(TIMEDIFF(ADDTIME(time_val, '120:00:00'), NOW()), '%Hh %im %ss') < 0 THEN '4' ELSE '0' END
WHERE id2 = '2' AND status = '0'
In the query you wrote, your subquery will get back the new time_val and the id number of the row to update, for any rows that match the criteria id2 = '2' AND status = '0'. You will then update all those rows (that matched the above criteria) and set the status to the new time_val.
Instead of selecting them first, cut out the middle man and just update all rows that match that criteria with the new value. Your query will be faster and more straightforward.
Besides the simplified version (provided by #Travesty3), it seems you are using a whole bunch of date and time functions to test for a simple thing:
UPDATE table1
SET status = '4'
WHERE id2 = '2'
AND status = '0'
AND time_val < NOW() - INTERVAL 120 HOUR
We can update table with multiple row by same table or two different table in this manner, just posting a snippet of mysql code from my procedure
Update documentcolumns as tb1, documentcolumns as tb2 set tb1.documentColumnPos = tb2.documentColumnPos Where tb1.userID = user_id and tb2.userID is NULL and tb1.columnNameDefID= tb2.columnNameDefID and tb1.tabtype = tab_type and tb2.tabtype = tab_type;,