Foxpro complex sub query - mysql

I'm having a hard time doing a query in foxpro 2.6 (no other choice)
note from some reason union queries do not work.
stockw (item, qte, dat) item is key
shist (item, qte, date) each row is a purchase for item and qte and date
the below query will calculate the first purchase for an item in shist to know how many months we've been selling every item since the beginning of the year
select shist.item as s_item, MIN(shist.date),stockw.qte as qte_remain,;
IIF( YEAR(MIN(shist.date)) < 2013, MONTH(DATE()), MONTH(DATE())-MONTH(shist.date)+1 ) as months;
FROM shist,stockw;
WHERE (shist.item LIKE 'LF-TK%' OR shist.item LIKE 'PL%' OR shist.item LIKE 'LF-A%') AND stockw.item = shist.item;
GROUP BY shist.item;
into CURSOR x
i want to:
- calculate the average qte from the beginning of the year 2013 till now for each item SUM(shist.qte)/months (months is calculated from the above query for each item)
maybe in a different query i want the below:
- select the max of sum of shist.qte for every month for each item (get highest month) from the beginning of the year 2013 till now.

Since I'm not quite following where you would be applying a union, and appears you have multiple times you are running the query, here is a VERY OLD trick that was usable in the old days of VFP...
When you do a select into cursor, the cursor is typically read-only and not read-write to append to... BUT, if you use the result of the first time run query AGAIN as a different alias, you CAN append to it. Something along the lines of...
use in select( "C_ThisIsMaster" )
for i = 1 to 10
use in select( "C_ThisRun" )
select blah, blah2, blah3 ;
from YourTables;
where SomeKey = SomeIDForCyclei;
into cursor C_ThisRun
if not used( "C_ThisIsMaster" )
select 0
use ( dbf( "C_ThisRun") ) again alias C_ThisIsMaster
else
select C_ThisIsMaster
append from dbf( "C_ThisRun" )
endif
endfor
The for[i] loop is just a sample, but if you are running for many cycles that you would do the UNION for, you can just pull that into a query and simulate the same, such as via
select *
from SomeTable
where SomeCondition
into cursor C_DoTheseItems
use in select( "C_ThisIsMaster" )
select C_DoTheseItems
do while not eof()
Do the same thing as inside the FOR loop above
select C_DoTheseItems
skip
enddo
I know VFP has scan/endscan, but don't remember how far back that originated, so using the do while NOT eof() was used here...
At the end of either option would give you a simulated UNION of each item you were trying to process into one "alias" result "C_ThisIsMaster" to work with

Related

Calculate Sum of Mean and Std dev in sql query on single column

I am having table name as "Table1" in mysql.I have to find Sum of Mean and Std dev on column "Open".I did it easily using python but I am unable to do it using sql.
Select * from BANKNIFTY_cal_spread;
Date Current Next difference
2021-09-03 00:00:00 36914.8 37043.95 129.14999999999418
2021-09-06 00:00:00 36734 36869.15 135.15000000000146
2021-09-07 00:00:00 36572.9 36710.65 137.75
2021-09-08 00:00:00 36945 37065 120
2021-09-09 00:00:00 36770 36895.1 125.09999999999854
Python Code-
nf_fut_mean = round(df['difference'].mean())
print(f"NF Future Mean: {nf_fut_mean}")
nf_fut_std = round(df['difference'].std())
print(f"NF Future Standard Deviation: {nf_fut_std}")
upper_range = round((nf_fut_mean + nf_fut_std))
lower_range = round((nf_fut_mean - nf_fut_std))
I search for Sql solution but I didn't get it. I tried building query but it's not showing correct results in query builder in grafana alerting.
Now I added Mean column ,std dev column , upper_range and lower_range column using python dataframe and pushed to mysql table.
#Booboo,
After removing Date from SQL Query, it's showing correct results in two columns- average + std_deviation and average - std_deviation.
select average + std_deviation, average - std_deviation from (
select avg(difference) as average, stddev_pop(difference) as std_deviation from BANKNIFTY_cal_spread
) sq
It looks as though the sample you're using for the aggregations for MEAN, STDDEV, etc is the entire table - in which case you have to drop the DATE field from the query's result set.
You could also establish the baseline query using a CTE (Common Table Expression) using a WITH statement instead of a subquery, and then apply the subsequent processing:
WITH BN_CTE AS
(
select avg(difference) as average, stddev_pop(difference) as std_deviation from BANKNIFTY_cal_spread
)
select average + std_deviation, average - std_deviation from BN_CTE;
With the data you posted having only a single Open column value for any given Date column value, you standard deviation should be 0 (and the average just that single value).
I am having difficulty in understanding your SQL since I cannot see how it relates to finding the sum (and presumably the difference, which you also seem to want) of the average and standard deviation of column Open in table Table1. If I just go by your English-language description of what you are trying to do and your definition of table Table1, then the following should work. Note that since we want both the sum and difference of two values, which are not trivial to calculate, we should calculate those two values only once:
select Date, average + std_deviation, average - std_deviation from (
select Date, avg(Open) as average, stddev_pop(Open) as std_deviation from Table1
group by Date
) sq
order by Date
Note that I am using column aliases in the subquery that do not conflict with built-in MySQL function names.
SQL does not allow both calculating something in the SELECT clause and using it. (Yes, #variables allow in limited cases; but that won't work for aggregates in the way hinted in the Question.)
Either repeat the expressions:
SELECT average(difference) AS mean,
average(difference) + stddev_pop(difference) AS "mean-sigma",
average(difference) - stddev_pop(difference) AS "mean+sigma"
FROM BANKNIFTY_cal_spread;
Or use a subquery to call the functions only once:
SELECT mean, mean-sigma, mean+sigma
FROM ( SELECT
average(difference) AS mean,
stddev_pop(difference) AS sigma
FROM BANKNIFTY_cal_spread
) AS x;
I expect the timings to be similar.
And, as already mentioned, avoid using aliases that are identical to function names, etc.

MYSQL SUM, value has to change on condition

I have a "CONTRACTS" table in which the user can select whether a Contract is "ANUAL" or "MONTHLY" (working on MariaDB/phpmyadmin)
The data is stored in the following manner:
CONTRACT
PERIOD
CICLE
SALE PRICE
CATEGORY
001
1
YEARLY
12000
CAT1
002
1
MONTHLY
1000
CAT2
I want to make a report that tells me the SUM of monthly contracts by CATEGORY
RIGHT NOW, THIS QUERY BELOW WORKS but its useless, since its doing SUM of "yearly" contracts along with monthly contracts
SELECT SUM(contracts.salesprice), `categories`.*
FROM `contracts`
LEFT JOIN `categories` ON `contratos`.`cat_id` = `categories`.`id_cat`
GROUP BY categorias.descripcion_cat;1
I'm a newbie and so far I was fine with INSERT, SELECT, UPDATE, DELETE;
I tried reading all documentation about CASE or IF, but I cant figure how to tell mysql to SUM based AND calculate on conditions
when CICLE = YEARLY then SALEPRICE /12 (to get the monthly value)
You were on the correct track with CASE.
The following code snippet will convert your yearly sales prices into monthly:
SUM(
CASE
WHEN contracts.cicle = 'YEARLY' THEN (contracts.salesprice / 12)
WHEN contracts.cicle = 'MONTHLY' THEN contracts.salesprice
ELSE 0
END
)
To use it in your query, simply replace your SUM(...) with that one.
To explain what it is doing, the CASE statement has several WHEN conditions. It uses the value of the first one that is true, if none are true, it will use the ELSE value (which you can change if you don't like 0). All of those resulting values are then summed up with SUM.
The benefit of CASE over IF is that CASE can be expanded as needed if you need more calculations for bi-annual, quarter, etc.

How do I group a table of datetimes together as long as there is a continuous chain at least every hour?

I have a table called 'events'.
It contains eventID (INT), eventDateTime(DATETIME), and eventMessage(VARCHAR).
I want to be able group the rows by eventDateTime where there is another row with eventDateTime within 1 hour each side. This should propogate forever (for example a group should be able go on for years, as long as there is never a gap longer than an hour between a linking chain of eventDateTime values within that time period. Ideally I want to end up selecting MIN(eventID) for each group, and both the MIN and MAX of eventDateTime which will give me the time span in which the group runs.
I assume I need some kind of iterating loop to do this? Where would I start?
Let's start from subqueries we need
SET #row_number1 = 0;
SET #row_number2 = 0;
The query returns us the events table ordered with row numbers (rn)
SELECT
(#row_number1:=#row_number1 + 1) AS rn, eventID, eventDateTime
FROM
events
ORDER BY eventDateTime
Let's mar them as SUB1 and SUB2
Then let's join them
select *
from SUB1 join SUB2 on sub1.rn=sub2.rn+1
So we have in one row 2 eventDateTime of current and next row and can calculate time difference
TIMESTAMPDIFF(HOUR, SUB1.eventDateTime, SUB2.eventDateTime) as hoursDiff
Then we can add HAVING hourDiff>1 to have rule breaking intervals. For such records SUB1.eventDateTime is the end of previous group but SUB2.eventDateTime is the beginning of next group.
So our query will return us
SUB1.eventID as previousGroupEndEventId,
SUB1.eventDateTime as previousGroupEndeventDateTime,
SUB2.eventID as currentGroupStartEventId,
SUB2.eventDateTime as currentGroupStarteventDateTime,
TIMESTAMPDIFF(HOUR, SUB1.eventDateTime, SUB2.eventDateTime) as breakInterval
And you can use the query results to get all your info
For complex problems requiring some form of looping, some databases allow recursive queries, but apparently not mysql.
Fortunately, in your case I don't think it is necessary. You can instead look for any rows which don't have another row in the preceeding hour thus:
select *
from events as A
where not exists (
select 1
from events as B
where B.eventDateTime < A.eventDateTime
and B.eventDateTime > DATE_ADD(A.eventDateTime, INTERVAL -1 HOUR)
)
Example kept simple. Fix up the details to meet your requirements.
Working example is here: http://sqlfiddle.com/#!9/c3b73c/1

Calculating time difference between activity timestamps in a query

I'm reasonably new to Access and having trouble solving what should be (I hope) a simple problem - think I may be looking at it through Excel goggles.
I have a table named importedData into which I (not so surprisingly) import a log file each day. This log file is from a simple data-logging application on some mining equipment, and essentially it saves a timestamp and status for the point at which the current activity changes to a new activity.
A sample of the data looks like this:
This information is then filtered using a query to define the range I want to see information for, say from 29/11/2013 06:00:00 AM until 29/11/2013 06:00:00 PM
Now the object of this is to take a status entry's timestamp and get the time difference between it and the record on the subsequent row of the query results. As the equipment works for a 12hr shift, I should then be able to build a picture of how much time the equipment spent doing each activity during that shift.
In the above example, the equipment was in status "START_SHIFT" for 00:01:00, in status "DELAY_WAIT_PIT" for 06:08:26 and so-on. I would then build a unique list of the status entries for the period selected, and sum the total time for each status to get my shift summary.
You can use a correlated subquery to fetch the next timestamp for each row.
SELECT
i.status,
i.timestamp,
(
SELECT Min([timestamp])
FROM importedData
WHERE [timestamp] > i.timestamp
) AS next_timestamp
FROM importedData AS i
WHERE i.timestamp BETWEEN #2013-11-29 06:00:00#
AND #2013-11-29 18:00:00#;
Then you can use that query as a subquery in another query where you compute the duration between timestamp and next_timestamp. And then use that entire new query as a subquery in a third where you GROUP BY status and compute the total duration for each status.
Here's my version which I tested in Access 2007 ...
SELECT
sub2.status,
Format(Sum(Nz(sub2.duration,0)), 'hh:nn:ss') AS SumOfduration
FROM
(
SELECT
sub1.status,
(sub1.next_timestamp - sub1.timestamp) AS duration
FROM
(
SELECT
i.status,
i.timestamp,
(
SELECT Min([timestamp])
FROM importedData
WHERE [timestamp] > i.timestamp
) AS next_timestamp
FROM importedData AS i
WHERE i.timestamp BETWEEN #2013-11-29 06:00:00#
AND #2013-11-29 18:00:00#
) AS sub1
) AS sub2
GROUP BY sub2.status;
If you run into trouble or need to modify it, break out the innermost subquery, sub1, and test that by itself. Then do the same for sub2. I suspect you will want to change the WHERE clause to use parameters instead of hard-coded times.
Note the query Format expression would not be appropriate if your durations exceed 24 hours. Here is an Immediate window session which illustrates the problem ...
' duration greater than one day:
? #2013-11-30 02:00# - #2013-11-29 01:00#
1.04166666667152
' this Format() makes the 25 hr. duration appear as 1 hr.:
? Format(#2013-11-30 02:00# - #2013-11-29 01:00#, "hh:nn:ss")
01:00:00
However, if you're dealing exclusively with data from 12 hr. shifts, this should not be a problem. Keep it in mind in case you ever need to analyze data which spans more than 24 hrs.
If subqueries are unfamiliar, see Allen Browne's page: Subquery basics. He discusses correlated subqueries in the section titled Get the value in another record.

mysql - set value of cell equal to value of cell in another row

I have a MySQL query that generates a table for my vehicle tracking 'in' and 'out' times.
The problem is that the 'in' time is not the same as the 'out' time so seconds or minutes are lost in between.
Is there a way to set the 'in' time equal to the 'out time' from the previous row, even if I need to embed my current select inside a new select?
you will see on the image below that the first rows out time is 15:45:14 and the in time for the next row is 15:46:14. so in this case a minute is lost
in reality if the vehicles has left one point, it is immediately on the road to the next point so I can set the in time equal to the out time of the previous row. This way, time is never lost
the sql for my query is:
select vehicle,InTime,OutTime from (select
PreQuery.callingname as vehicle,
PreQuery.geofence,
PreQuery.GroupSeq,
MIN( PreQuery.`updatetime` ) as InTime,
UNIX_TIMESTAMP(MIN( PreQuery.`updatetime`))as InSeconds,
MAX( PreQuery.`updatetime` ) as OutTime,
UNIX_TIMESTAMP(MAX( PreQuery.`updatetime`))as OutSeconds,
TIME_FORMAT(SEC_TO_TIME((UNIX_TIMESTAMP(MAX( PreQuery.`updatetime` )) - UNIX_TIMESTAMP(MIN( PreQuery.`updatetime`)))),'%H:%i:%s') as Duration,
(UNIX_TIMESTAMP(MAX( PreQuery.`updatetime` )) - UNIX_TIMESTAMP(MIN( PreQuery.`updatetime`))) as DurationSeconds
from
( select
v_starting.callingname,
v_starting.geofence,
v_starting.`updatetime`,
#lastGroup := #lastGroup + if( #lastAddress = v_starting.geofence
AND #lastVehicle = v_starting.callingname, 0, 1 ) as GroupSeq,
#lastVehicle := v_starting.callingname as justVarVehicleChange,
#lastAddress := v_starting.geofence as justVarAddressChange
from
v_starting,
( select #lastVehicle := '',
#lastAddress := '',
#lastGroup := 0 ) SQLVars
order by
v_starting.`updatetime` ) PreQuery
Group By
PreQuery.callingname,
PreQuery.geofence,
PreQuery.GroupSeq) parent
where (InTime> DATE_SUB('2013-03-23 15:00', INTERVAL 24 HOUR) or OutTime> '2013-03-23 15:00' ) and vehicle='TT08' order by InTime asc
The MySQL syntax is in depth so quite large but could be done on a much simpler query as well. like
select vehicle, intime,outtime from vehicletimes
My desired result is something like:
select vehicle, intime(outtime of row above),outtime from vehicletimes
The first rows in time can be as is and the last rows outtime can be as is. I just need to account for every second between the smallest in time and the largest out time.
Any help appreciated as always.
Thanks in advance
I think this will give you the latest in-time prior to each current out-time, for your existing records:
select
vt.vehicle, max(qGetMaxOut.outtime) as intime , vt.outtime
from
vehicle_times vt
inner join
(
select vehicle, outtime
from vehicle_times
) qGetMaxOut
on qGetMaxOut.vehicle = vt.vehicle
and qGetMaxOut.outtime <= vt.intime
group by
vt.vehicle, vt.outtime
The above query will also help you if you want to insert a new record, but need to find the previous in-time for a particular time (ie if you need to insert a new record who's in/out times are prior to the latest time - eg inserting a record that was somehow previously missed and where newer time entries have been added since). If you need this scenario, let me know and I'll elaborate if you can't work it out from the above.
The join basically joins the table "back on itself" to provide another "copy", but limits the results in the "copy" to only those rows for the current vehicle in the main table, and excludes those rows from the copy where the vehicle's out-time is more recent than the current in-time from the main table. This way you can do a MAX() over the copy, to find what the previous out time was.
I don't know your specific requirements, but I would recommend storing the most accurate information you can. So if "sythensising" a value is just for cosmetic purposes on a few reports, I would leave the data alone, and tidy up the report, rather than loosing data that might come in handy down the track. eg what happens if in the future, you suddenly have a requirement to tell your boss "how long are our vehicles 'in' and sitting idle for?"
But if you do just want to insert a new record with the actual out-time ignored, and replaced by the in-time from the most recent record, then this following query will find that value for you:
select
vt.vehicle, max(vt.outtime) as intime
from
vehicle_times vt
group by
vt.vehicle
Have I missed your requirement?