MySql Query for generating report - mysql

I have one table which is having three fields:
Id, Creation Time, Fuel Level
Every two minutes we are getting data and inserting to database.For generating a fuel credit/debit statement i want to get starting(Stating of the day) and ending(End of the Day) Fuel Level.Can anyone help to form a query to generate this report?
Search parameters will be date range.
Id=10;creation time =2019-02-15 16:32:59;Fuel Level =20
I created one sample schema here
http://sqlfiddle.com/#!2/76dd5

First, for a query that provides the change in fuel for each vehicle for each day, you can use the following SQL:
SELECT trip_range.dt
, trip_range.vehicle_id
, st.fuel_content as start_fuel_content
, en.fuel_content as end_fuel_content
, en.fuel_content - st.fuel_content as fuel_change
FROM (
SELECT tp.vehicle_id, DATE(tp.creation_time) dt
, MIN(tp.creation_time) start_time
, MAX(tp.creation_time) end_time
FROM trip_parameters tp
GROUP BY tp.vehicle_id, DATE(tp.creation_time)
) as trip_range
JOIN trip_parameters st
ON st.vehicle_id = trip_range.vehicle_id
AND st.creation_time = trip_range.start_time
JOIN trip_parameters en
ON en.vehicle_id = trip_range.vehicle_id
AND en.creation_time = trip_range.end_time
WHERE trip_range.dt BETWEEN '2012-11-08' AND '2012-11-09'
If you want the Cumulative change in fuel across all vehicles for each day in the range, the following SQL should work:
SELECT dt, SUM(fuel_change) as fuel_change
FROM (
SELECT trip_range.dt
, en.fuel_content - st.fuel_content as fuel_change
FROM (
SELECT tp.vehicle_id, DATE(tp.creation_time) dt
, MIN(tp.creation_time) start_time
, MAX(tp.creation_time) end_time
FROM trip_parameters tp
GROUP BY tp.vehicle_id, DATE(tp.creation_time)
) as trip_range
JOIN trip_parameters st
ON st.vehicle_id = trip_range.vehicle_id
AND st.creation_time = trip_range.start_time
JOIN trip_parameters en
ON en.vehicle_id = trip_range.vehicle_id
AND en.creation_time = trip_range.end_time
WHERE trip_range.dt BETWEEN '2012-11-08' AND '2012-11-09'
) change_by_vehicle
GROUP BY 1
Hope this helps!
john...

Try below:
SELECT Id, CreationTime, FuelLevel
FROM MYTABLE
WHERE DATE(CreationTime) = CURDATE();
This gets the date part of CreationTime and compares against current date, thus returns all records created today.

here's a query that returns the output as:
DATE FUEL_CONTENT_AT_START_OF_DAY FUEL_CONTENT_AT_END_OF_DAY
Nov, 08 2012 4.6 3.6
Nov, 09 2012 11.6 5.6
Query
SELECT
DATE( startofday.creation_time) AS date,
startofday.fuel_content AS fuel_content_at_start_of_day,
(SELECT fuel_content FROM trip_parameters WHERE trip_paramid = max(endofday.trip_paramid) ) AS fuel_content_at_end_of_day
FROM
trip_parameters startofday
INNER JOIN trip_parameters endofday ON ( DATE( endofday.creation_time ) = DATE( startofday.creation_time) )
WHERE
DATE( startofday.creation_time) BETWEEN '2012-11-08' AND '2012-11-09'
GROUP BY
startofday.TRIP_PARAMID
HAVING
min( endofday.trip_paramid ) = startofday.trip_paramid
I have update the same on SQLFiddle, http://sqlfiddle.com/#!2/76dd5/67
The query works as
Get a row
Get all corresponding rows on the same day
Get the minimum and maximum ID on the same day
If the current row Id equals the minimum Id from the JOIN display it, else ignore
Use the maximum id in a sub-query to get the end of day fuel_content
Hope this helps

Related

mysql max and min subquery using date range

I have the following query:
SELECT
(Date + INTERVAL -(WEEKDAY(Date)) DAY) `Date`,
I would like to use a subquery here to get the oldest and newest inventory from the max and min Date:
(select sellable from clabDevelopment.fba_history_daily where Date =
max(Date))
max(Date), min(Date),
ASIN,
ItemSKU,
it.avgInv,
kt.Account, kt.Country, SUM(Sessions) `Sessions`, avg(Session_Pct)`Session_Pct`,
sum(Page_Views)`Page_Views`, avg(Page_Views_Pct)`Page_Views_Pct`, avg(Buy_Box_Pct)`Buy_Box_Pct`,
sum(Units_Ordered)`Units_Ordered`, sum(Units_Ordered_B2B) `Units_Ordered_B2B`,
avg(Unit_Session_Pct)`Unit_Session_Pct`, avg(Unit_Session_Pct_B2B)`Unit_Session_Pct_B2B`,
sum(Ordered_Product_Sales)`Ordered_Product_Sales`, sum(Total_Order_Items) `Total_Order_Items`, sum(Actual_Sales) `Actual_Sales`,
sum(Orders) `Orders`, sum(PPC_Revenue) `PPC_Revenue`, sum(PPC_Orders) `PPC_Orders`,
sum(Revenue)`Revenue`, sum(Sales_Tax_Collected) `Sales_Tax_Collected`, sum(Total_Ad_Spend) `Total_Ad_Spend`, sum(Impressions) `Impressions`,
sum(Profit_after_Fees_before_Costs) `Profit_after_Fees_before_Cost`
FROM clabDevelopment.KPI_kpireport as kt
left outer join
(SELECT Month(Date) as mnth, sku, account, country, avg(sellable)`avgInv` FROM clabDevelopment.`fba_history_daily`
where sellable >= 0
group by Month(Date), sku, account, country) as it
on kt.ItemSKU = it.SKU
and kt.Account = it.account
and kt.Country = it.country
and it.mnth = Month(kt.Date)
WHERE kt.Country = 'USA' or kt.Country = 'CAN'
GROUP BY Account, Country,(Date + INTERVAL -(WEEKDAY(Date)) DAY), ItemSKU
ORDER BY Date desc
The sub-query would be from the same table I am joining on the bottom except I group by month there. So I want to run this subquery and grab the value under sellable for the date of max(Date):
(select sellable from clabDevelopment.`fba_history_daily where Date = max(Date))
When I do it this way I get invalid use of group function.
Without known your schema and the engine/db it is difficult to understand the problem. But, here is a best guess with the following schema:
fba_history_daily
- mnth
- sku
- account
- country
- sellable
- SKU
KPI_kpireport
- Account
- Country
- ItemSKU
- Account
- Date
- Country
- ASIN
The following query would give you what you're looking for. This uses a GROUP_CONCAT in order to build the required results through aggregation. With the nested query join MySQL might be building a temporary table within memory to sort through those records which would not be optimal. You can check this using EXPLAIN and you would see Using temporary in the details.
SELECT
(Date + INTERVAL -(WEEKDAY(Date)) DAY) `Date`,
ASIN,
ItemSKU,
-- MIN
(SUBSTRING_INDEX(GROUP_CONCAT(it.sellable ORDER BY it.Date ASC),',', 1) AS minSellable),
-- MAX
(SUBSTRING_INDEX(GROUP_CONCAT(it.sellable ORDER BY it.Date DESC),',', 1) AS maxSellable),
-- AVG
AVG(it.sellable) avgInv,
kt.Account, kt.Country, SUM(Sessions) `Sessions`, avg(Session_Pct)`Session_Pct`,
sum(Page_Views)`Page_Views`, avg(Page_Views_Pct)`Page_Views_Pct`, avg(Buy_Box_Pct)`Buy_Box_Pct`,
sum(Units_Ordered)`Units_Ordered`, sum(Units_Ordered_B2B) `Units_Ordered_B2B`,
avg(Unit_Session_Pct)`Unit_Session_Pct`, avg(Unit_Session_Pct_B2B)`Unit_Session_Pct_B2B`,
sum(Ordered_Product_Sales)`Ordered_Product_Sales`, sum(Total_Order_Items) `Total_Order_Items`, sum(Actual_Sales) `Actual_Sales`,
sum(Orders) `Orders`, sum(PPC_Revenue) `PPC_Revenue`, sum(PPC_Orders) `PPC_Orders`,
sum(Revenue)`Revenue`, sum(Sales_Tax_Collected) `Sales_Tax_Collected`, sum(Total_Ad_Spend) `Total_Ad_Spend`, sum(Impressions) `Impressions`,
sum(Profit_after_Fees_before_Costs) `Profit_after_Fees_before_Cost`
FROM KPI_kpireport as kt
left outer join fba_history_daily it on
kt.ItemSKU = it.SKU
and kt.Account = it.account
and kt.Country = it.country
and Month(it.Date) = Month(kt.Date)
and it.sellable >= 0
WHERE kt.Country = 'USA' or kt.Country = 'CAN'
GROUP BY Account, Country,(Date + INTERVAL -(WEEKDAY(Date)) DAY), ItemSKU
ORDER BY Date desc

MySql - Selecting MAX & MIN and returning the corresponding rows

I trying to get the last 6 months of the min and max of prices in my table and display them as a group by months. My query is not returning the corresponding rows values, such as the date time for when the max price was or min..
I want to select the min & max prices and the date time they both occurred and the rest of the data for that row...
(the reason why i have concat for report_term, as i need to print this with the dataset when displaying results. e.g. February 2018 -> ...., January 2018 -> ...)
SELECT metal_price_id, CONCAT(MONTHNAME(metal_price_datetime), ' ', YEAR(metal_price_datetime)) AS report_term, max(metal_price) as highest_gold_price, metal_price_datetime FROM metal_prices_v2
WHERE metal_id = 1
AND DATEDIFF(NOW(), metal_price_datetime) BETWEEN 0 AND 180
GROUP BY report_term
ORDER BY metal_price_datetime DESC
I have made an example, extract from my DB:
http://sqlfiddle.com/#!9/617bcb2/4/0
My desired result would be to see the min and max prices grouped by month, date of min, date of max.. and all in the last 6 months.
thanks
UPDATE.
The below code works, but it returns back rows from beyond the 180 days specified. I have just checked, and it is because it joining by the price which may be duplicated a number of times during the years.... see: http://sqlfiddle.com/#!9/5f501b/1
You could use twice inner join on the subselect for min and max
select a.metal_price_datetime
, t1.highest_gold_price
, t1.report_term
, t2.lowest_gold_price
,t2.metal_price_datetime
from metal_prices_v2 a
inner join (
SELECT CONCAT(MONTHNAME(metal_price_datetime), ' ', YEAR(metal_price_datetime)) AS report_term
, max(metal_price) as highest_gold_price
from metal_prices_v2
WHERE metal_id = 1
AND DATEDIFF(NOW(), metal_price_datetime) BETWEEN 0 AND 180
GROUP BY report_term
) t1 on t1.highest_gold_price = a.metal_price
inner join (
select a.metal_price_datetime
, t.lowest_gold_price
, t.report_term
from metal_prices_v2 a
inner join (
SELECT CONCAT(MONTHNAME(metal_price_datetime), ' ', YEAR(metal_price_datetime)) AS report_term
, min(metal_price) as lowest_gold_price
from metal_prices_v2
WHERE metal_id = 1
AND DATEDIFF(NOW(), metal_price_datetime) BETWEEN 0 AND 180
GROUP BY report_term
) t on t.lowest_gold_price = a.metal_price
) t2 on t2.report_term = t1.report_term
simplified version of what you should do so you can learn the working process.
You need calculate the min() max() of the periods you need. That is your first brick on this building.
you have tableA, you calculate min() lets call it R1
SELECT group_field, min() as min_value
FROM TableA
GROUP BY group_field
same for max() call it R2
SELECT group_field, max() as max_value
FROM TableA
GROUP BY group_field
Now you need to bring all the data from original fields so you join each result with your original table
We call those T1 and T2:
SELECT tableA.group_field, tableA.value, tableA.date
FROM tableA
JOIN ( ... .. ) as R1
ON tableA.group_field = R1.group_field
AND tableA.value = R1.min_value
SELECT tableA.group_field, tableA.value, tableA.date
FROM tableA
JOIN ( ... .. ) as R2
ON tableA.group_field = R2.group_field
AND tableA.value = R2.max_value
Now we join T1 and T2.
SELECT *
FROM ( .... ) as T1
JOIN ( .... ) as T2
ON t1.group_field = t2.group_field
So the idea is if you can do a brick, you do the next one. Then you also can add filters like last 6 months or something else you need.
In this case the group_field is the CONCAT() value

Calculate Date by number of working days from a certain Startdate

I've got two tables, a project table and a calendar table. The first containts a startdate and days required. The calendar table contains the usual date information, like date, dayofweek, and a column is workingday, which shows if the day is a saturday, sunday, or bank holiday (value = 0) or a regular workday (value = 1).
For a certain report I need write a stored procedure that calculates the predicted enddate by adding the number of estimated workddays needed.
Example:
**Projects**
Name Start_Planned Work_days_Required
Project A 02.05.2016 6
Calendar (04.05 is a bank holdiday)
Day Weekday Workingday
01.05.2016 7 0
02.05.2016 1 1
03.05.2016 2 1
04.05.2016 3 0
05.05.2016 4 1
06.05.2016 5 1
07.05.2016 6 0
08.05.2016 7 0
09.05.2016 1 1
10.05.2016 2 1
Let's say, the estimated number of days required is given as 6 (which leads to the predicted enddate of 10.05.2016). Is it possible to join the tables in a way, which allows me to put something like
select date as enddate_predicted
from calendar
join projects
where number_of_days = 6
I would post some more code, but I'm quite stuck on how where to start.
Thanks!
You could get all working days after your first date, then apply ROW_NUMBER() to get the number of days for each date:
SELECT Date, DayNum = ROW_NUMBER() OVER(ORDER BY Date)
FROM Calendar
WHERE IsWorkingDay = 1
AND Date >= #StartPlanned
Then it would just be a case of filtering for the 6th day:
DECLARE #StartPlanned DATE = '20160502',
#Days INT = 6;
SELECT Date
FROM ( SELECT Date, DayNum = ROW_NUMBER() OVER(ORDER BY Date)
FROM Calendar
WHERE WorkingDay = 1
AND Date >= #StartPlanned
) AS c
WHERE c.DayNum = #Days;
It's not part of the question, but for future proofing this is easier to acheive in SQL Server 2012+ with OFFSET/FETCH
DECLARE #StartPlanned DATE = '20160502',
#Days INT = 6;
SELECT Date
FROM dbo.Calendar
WHERE Date >= #StartPlanned
AND WorkingDay = 1
ORDER BY Date
OFFSET (#Days - 1) ROWS FETCH NEXT 1 ROWS ONLY
ADDENDUM
I missed the part earlier about having another table, and the comment about putting it into a cursor has prompted me to amend my answer. I would add a new column to your calendar table called WorkingDayRank:
ALTER TABLE dbo.Calendar ADD WorkingDayRank INT NULL;
GO
UPDATE c
SET WorkingDayRank = wdr
FROM ( SELECT Date, wdr = ROW_NUMBER() OVER(ORDER BY Date)
FROM dbo.Calendar
WHERE WorkingDay = 1
) AS c;
This can be done on the fly, but you will get better performance with it stored as a value, then your query becomes:
SELECT p.Name,
p.Start_Planned,
p.Work_days_Required,
EndDate = c2.Date
FROM Projects AS P
INNER JOIN dbo.Calendar AS c1
ON c1.Date = p.Start_Planned
INNER JOIN dbo.Calendar AS c2
ON c2.WorkingDayRank = c1.WorkingDayRank + p.Work_days_Required - 1;
This simply gets the working day rank of your start date, and finds the number of days ahead specified by the project by joining on WorkingDayRank (-1 because you want the end date inclusive of the range)
This will fail, if you ever plan to start your project on a non working day though, so a more robust solution might be:
SELECT p.Name,
p.Start_Planned,
p.Work_days_Required,
EndDate = c2.Date
FROM Projects AS P
CROSS APPLY
( SELECT TOP 1 c1.Date, c1.WorkingDayRank
FROM dbo.Calendar AS c1
WHERE c1.Date >= p.Start_Planned
AND c1.WorkingDay = 1
ORDER BY c1.Date
) AS c1
INNER JOIN dbo.Calendar AS c2
ON c2.WorkingDayRank = c1.WorkingDayRank + p.Work_days_Required - 1;
This uses CROSS APPLY to get the next working day on or after your project start date, then applies the same join as before.
This query returns a table with a predicted enddate for each project
select name,min(day) as predicted_enddate from (
select c.day,p.name from dbo.Calendar c
join dbo.Calendar c2 on c.day>=c2.day
join dbo.Projects p on p.start_planned<=c.day and p.start_planned<=c2.day
group by c.day,p.work_days_required,p.name
having sum(c2.workingday)=p.work_days_required
) a
group by name
--This gives me info about all projects
select p.projectname,p.Start_Planned ,c.date,
from calendar c
join
projects o
on c.date=dateadd(days,p.Work_days_Required,p.Start_Planned)
and c.isworkingday=1
now you can use CTE like below or wrap this in a procedure
;with cte
as
(
Select
p.projectnam
p.Start_Planned ,
c.date,datediff(days,p.Start_Planned,c.date) as nooffdays
from calendar c
join
projects o
on c.date=dateadd(days,p.Work_days_Required,p.Start_Planned)
and c.isworkingday=1
)
select * from cte where nooffdays=6
use below logic
CREATE TABLE #proj(Name varchar(50),Start_Planned date,
Work_days_Required int)
insert into #proj
values('Project A','02.05.2016',6)
CReATE TABLE #Calendar(Day date,Weekday int,Workingday bit)
insert into #Calendar
values('01.05.2016',7,0),
('02.05.2016',1,1),
('03.05.2016',2,1),
('04.05.2016',3,0),
('05.05.2016',4,1),
('06.05.2016',5,1),
('07.05.2016',6,0),
('08.05.2016',7,0),
('09.05.2016',1,1),
('10.05.2016',2,1)
DECLARE #req_day int = 3
DECLARE #date date = '02.05.2016'
--SELECT #req_day = Work_days_Required FROM #proj where Start_Planned = #date
select *,row_number() over(order by [day] desc) as cnt
from #Calendar
where Workingday = 1
and [Day] > #date
SELECT *
FROM
(
select *,row_number() over(order by [day] desc) as cnt
from #Calendar
where Workingday = 1
and [Day] > #date
)a
where cnt = #req_day

postgresql to mssql query conversion

can any one help me to convert the following query into mssql which is working on postgresql now
query is to take the updated datetime of the report in the asc order of the date
select
count(*) as count,
TO_CHAR(RH.updated_datetime,'dd-mm-YYYY') as date,
SUM(
extract (
epoch from (
RH.updated_datetime - PRI.procedure_performed_datetime
)
)
)/count(*) as average_reporting_tat
from
report R,
report_history RH,
study S,
procedure_runtime_information PRI,
priorities PP,
patient P,
procedure PR
where
RH.report_fk=R.pk and RH.pk IN (
select pk from (
select * from report_history where report_fk=r.pk order by revision desc limit 1
) as result
where old_status_fk IN (21, 27)
) AND R.study_fk = S.pk
AND S.procedure_runtime_fk = PRI.pk
AND PRI.procedure_fk = PR.pk
AND S.priority_fk = PP.pk
AND PRI.patient_fk = P.pk
AND RH.updated_datetime >= '2013-05-01'
AND RH.updated_datetime <= '2013-05-12'
group by date
If I read your query properly, your problem is that you need to list everything in the group by clause that is in your column list which is not part of an aggregate. So your group by needs to be:
GROUP BY RH.updated_datetime
If this doesn't fix it, please post the error message you are getting.

MySql - Selecting First And Last Row (Not Min/Max)

I have a MySql table with daily stock market data in the following order:
_date, _opening_price, _high_price, _low_price, _close_price
I'm trying to transform this data into weekly data by using:
SELECT
MAX(_date) AS _date,
WEEK(_date) AS weeknum,
_opening_price,
MAX(_high_price) AS _high_price,
MIN(_low_price) AS _low_price,
_closing_price
FROM myTable
GROUP BY weeknum ORDER BY _date;
How do I select _opening_price so that it is the first _opening_price from within that week's daily data? Likewise, how do I select _closing_price so that it is the last _closing_price within the week's daily data?
Here's an example:
For week ending 2007-01-05, the opening_price should be taken from 2007-01-03 (red) and the closing price should be taken from 2007-01-05 (green). Similarly, for week ending on 2007-01-12, opening price should be from 2007-01-08 and closing price from 2007-01-12.
Try this solution:
SELECT
MAX(a._date) weekending,
MAX(CASE WHEN a._date = b.mindate THEN a._opening_price END) openingprice,
MAX(CASE WHEN a._date = b.maxdate THEN a._closing_price END) closingprice
FROM myTable a
INNER JOIN
(
SELECT
CONCAT(YEAR(_date), '-', WEEK(_date)) weeknum,
MIN(_date) mindate,
MAX(_date) maxdate
FROM myTable
GROUP BY weeknum
) b ON a._date IN (b.mindate, b.maxdate)
GROUP BY b.weeknum