How can I create a timeline in Access? - ms-access

In Access I have an MachinesList and ActionsList. A Machine can be set to Active and set to Inactive several times per year. Each change of status has its own ActionID and ActionDate.
In VBA I added some code to get the first and last date the Machine is Active. As this can happen more than once I now can create a list with start- and enddates each time the Machine is Active.
Two questions:
1) Can this be done with a query instead of VBA?
2) Is it possible to display these dates in some sort of timeline in Access?
This is what I have to create my list of dates:
SELECT DISTINCT Requests.RequestNumber, Requests.MachineID, Actions.Assignee, Actions.Action, Actions.TRDate FROM SelectedIDs LEFT JOIN (Requests LEFT JOIN Actions ON Requests.RequestNumber = Actions.RequestNumber) ON SelectedIDs.MachineID = Requests.MachineID ORDER BY Requests.MachineID, Actions.TRDate;
I do need the RequestNumber and the Assignee (in case of Activation) for further use. And since the RequestNumber for Activation and Deactivation differ I cannot use the MIN(date) and MAX(date) functionality because of the GROUP BY clause.
The list produced in VBA looks somewhat like this:
2325 ID1234 29-11-2016 16-3-2017
2323 ID1234 28-3-2017 27-4-2017
2203 ID9999 25-1-2017 27-2-2017
This list I want to see in some sort of timeline in Access.
Something like this:
ID | wk01 | wk02 | wk03 | etc
88 | N | N | Y | Y | Y | N
99 | N | Y | Y | N | N | Y
But any timeline is fine. Suggestions anyone?
Thanks, Karin

It is possible to do, yes. Your resulting recordset will not be tabular, it will be more like { Week, MachineID, Active } and it will be up to you to format it for reporting purposes. It may take a few subqueries, for example an obvious one is max of activation date before the week's end, and min de-activation date after that activation date. If that deactivation date is before the week's start the machine was not active. The actual SQL depends on how your Week table is defined. If you don't have a week table things get a bit more complicated as you also need a sub-query that replaces the week table.

Related

candle creation on a monthly basis using the scores in mysql

I am trying to create a candle using the table as below. It has a score and month and there can be as many as 4 scores in a month.
id | score | month
1 | 10 | 12
.. | .. | ..
And here is what I actually did,
select
score as open,
max(score) as high,
min(score) as low
from score_table
group by month
I am successful in getting Open, high and low.
My problem is getting the close, basically the fourth score of a month. I tried some solutions using joins unfortunately I am wrong and couldn't get it right which actually landed me in too many confusion. I'm not good at SQL and need help...
I see when you group by month the records just give you a high and a low with the same values
What I changed is to get the month and the high and low .
There should be separate columns for the high ,low and open in a list form to break the high lows up per time period (if you only working on one candle its fine but many candles over a time period there should be a row for each time period)
that data is quite hard to work with the way the table is set out but you can construct something like this to make it easier for your self
id | Month | Open | High | Low |
would be more ideal to work with that data but non the the least I changed the the MySQL query a bit to reflect data as per your description. I achieved it by combining 2 MySQL queries to get the open data from row 3
select x.open, y.high, y.low from ( select (score) as open
from score
where id = 3 )as x,
(select max(score) as high,
min(score) as low
from score ) as y;

Using Lookup and getting a count from each Dataset

I have two datasets and I'm using Lookup to get one result, but the total is only from one dataset. I've tried and tried, but I'm having no luck.
First Dataset is called MedCond
This is the Data:
Drug_Name
Start_Date
Stop_Date
InmateID
Drug_Indication
Created
ID
Second Dataset is called ProblemList
This is the Data:
Medical_Condition
Inmate_ID
Created
ID
Drug Indication and Medical Condition are the same. I want to get a combined total of both.
This only gives me the count of the Drug Indications (which I have them grouped on) =Count(Lookup(Fields!Drug_Indication.Value,Fields!Medical_Condition.Value,Fields!Medical_Condition.Value, "ProblemList"))
I feel like I've tried everything under the sun. I'm extremely exasperated. I'm trying to get a total of each of the conditions/Indications that come from each dataset. For instance, One condition/Indication might be Addiction. There may be four addictions in from the Drug_Indication in the MedCon dataset and five addictions from the Medical_Condition in the ProblemList. I want to see Addictions 9 on the table and so and so forth for each Drug Indication/Medical Condition.
Thanks in advance for your help! Save my sanity. :) I'm sure it's probably something simple?
Tara
Thank you. I've tried using the Inmate_ID and InmateID as the key to join, but I still end up with only one of counts of either Medical_Condition or Drug_Indication.
As an example, there might be 10 addictions in one and 15 addictions in the other. I need them to be grouped under the title addiction (and whatever other titles there might be) with the total being 25.
It would look something like this.
Example Look
Something like this is close, but the counts aren't quite right.
=Count(Lookup(Fields!InmateID.Value, Fields!Inmate_ID.Value, Fields!Medical_Condition.Value, "ProblemList")) + Count(Fields!Drug_Indication.Value)
Maybe it's the way I'm grouping? How do you group on a combination of values such as Medical_condition and Drug_Indication?
Thanks again!
Tara
I think you used the Lookup() wrong. When I look at your two datasets (for me) the key to join the two datasets would be Inmate_ID.
=Lookup(Fields!InmateID.Value, Fields!Inmae_ID.Value, Fields!Medical_Condition.Value, "SecondDatasetName")
This would result in a table like this (The last column comes form the lookup above):
Drug_Name | Start_Date | Stop_Date | InmateID | Drug_Indication | Created | ID | Medical_Condition
Now you can just get the total per column:
Drug_Name | Start_Date | Stop_Date | InmateID | Drug_Indication | Created | ID | Medical_Condition
Total1 Total2
To sum Total1 and Total2 you can add a new tablix and reference to the textbox totals like this:
=ReportItems!Total1TextboxName.Value + ReportItems!Total2TextboxName.Value

MS Access : multiple queries into one table

Okay I'm still fairly new to MS Access, but have got some of the bases down. My next issue is pulling data from two different queries but still needing them to show.
Here's what I have
I have one query with the following information
| ID Number | Points |
The other query has the following
| ID Number | Points over 1000 |
In this new query I need to do display the following
| ID Number | Points | Points over 1000 | Total Points |
There's going to be some rows where Points over 1000 doesn't exist and needs to be empty or a 0, but I need the ID Number In Points over 1000 to match and check the ID Number in just the points column.
and in the end add them up in the Points total
I hope that makes sense?
Thanks again
In theory this Query should work the way you want it to.
SELECT
tmpQ.ID,
Sum(tmpQ.Points) As ActualPoints,
Sum(tmpQ.PointsOver1000) As Over1000,
[ActualPoints] + [Over1000] As TotalPoints
FROM
(
SELECT
qryA.[ID Number] As ID,
Sum(qryA.Points) As Points,
Sum(0) As PointsOver1000
FROM
qryA
GROUP BY
qryA.[ID Number]
UNION ALL
SELECT
qryB.[ID Number] As ID,
Sum(0) As Points,
Sum(qryB.PointsOver1000) As PointsOver1000
FROM
qryB
GROUP BY
qryB.[ID Number]
) As tmpQ
GROUP BY
tmpQ.ID;
Where qryA and qryB are the two queries you have that will give you the result of two different Points.

SQL for time periods

I have statistic table for internet radio (MySQL), there are such columns:
ip_address
time_start (datetime of listening start)
time_end (datetime of listening finish)
I need to select the listeners peak for each day, I mean maximum number of simultaneous unique ip listeners.
And it would be great also to have start and finish time for that peak.
For example:
2011-30-01 | 4 listeners peak | from 10:30 | till 11:25
IMHO it's simpler to load these 35'000 rows in memory, enumerate them, and maintain a count of the concurrent listener at a given moment.
This would be simpler if you load the row in the following format:
IP, Time, flag_That_Indicate_StartOrStop_Listening_For_This_Given_IP
so you'll be able to load the data ordered by time, and the you should simply enumerate all rows maintaining a list of listening IP.
Anyway, how do you consider multiple connections from the same IP?
There can be 10 different listeners behind a NAT using the same IP address.
Update:
You don't really need to change the DB structure, it's enough use a different SQL to load the data
SELECT ip_address, Time_Start AS MyTime, 1 As StartStop
FROM MyTable
ORDER BY Time_Start
UNION ALL
SELECT ip_address, Time_Stop AS MyTime, 0 As StartStop
FROM MyTable
Using this SQL you should be able to load all the data, and then enumerate all the rows.
It's important that the rows are sorted correctly.
if StartStop = 1 it's somone that start listening --> Add it's IP to the list of listeners, and increment the listeners count by 1
if StartStop = 0 it's someone that stop listening --> remove it's IP from the list of listeners, and decrement the listeners count by 1
and in the enumeration loop check when you reach the maximum number of concurrent listeners
Let go to find for an algorithm to get results with best performance.
Spliting time: Time is a continuous dimension, we need some points to mark as checkpoint where do a listener recount. How to find intervals or when check for total radio listener. I thing that the best strategy is to get different time_start and time_end.
This is my approach to split time. I create a view to simplify post:
create view time_split as
select p_time from (
Select
time_start
from
your_table
union
Select
time_end
from
your_table
) as T
I suggest to you 2 database index:
your_table( time_start, time_end) <--(1) explained below
your_table( time_end)
to avoid tablescan.
Count listeners peak: Join previous table with your table to do a recount of peak at each time checkpoint:
This is my approach for count listeners by check point time:
create view peak_by_time as
select p_time, count(*) as peak
from
your_table t
inner join
time_split
on time_split.p_time between t.time_start and t.time_end
group by
p_time
order by
p_time, peak
Remember to make a database index on your_table( time_start, time_end) <--(1) Here
Looking for max peak: Unfortunately MySQL don't has analytic functions, then over partition is not available and is not a way to take max peak over a day in previous view. Then you should get max peak of previous views. This is a performance killer operation. I suggest to you make this operation and next on in application logic and not in data base.
This is my approach for get max_peak by day (performance killer):
create view max_peak_by_day as
select
cast(p_time as date) as p_day ,
max(peak) as max_peak
from peak_by_time
group by cast(p_time as date)
Looking for slot times: at this moment you have max_peak for each day, now you need to look for continuous check times with same max_peak. Also MySQL don't has statistical functions neither CTE. I suggest to you that this code will be wrote on app layer. But, if you want to do this in database solution this is a way (warning performance killer):
First, extend peak_by_time view to get previous peak for p_time and for previous p_time:
create view time_split_extended as
select c.p_time, max( p.p_time) as previous_ptime
from
time_split c
inner join
time_split p
on p.p_time < c.p_time
group by c.p_time
create view peak_by_time_and_previous as
select
te.p_time,
te.previous_ptime,
pc.peak as peak,
pp.peak as previous_peak
from
time_split_extended te
inner join
peak_by_time pc on te.p_time = pc.p_time
inner join
peak_by_time pp on te.previous_ptime = pp.p_time
Now check that previous slot and current one have a max_peak:
select
cast(p_time as date) as p_day,
min( p_time ) as slot_from,
max( p_time) as slot_to,
peak
from
peak_by_time_and_previous p
inner join
max_peak_by_day m
on cast(p.p_time as date) = m.p_day and
p.peak = m.max_peak
where
p.peak = p.previous_peak
group by cast(p_time as date)
Disclaimer:
This is not tested. Sure that they are mistakes with table aliases or columns.
The last steps are performance killers. Perhaps someone can suggest best approach for this steps.
Also, I suggest to you that create temporary tables and materialize each view of this answer. This will improve performance and also you can know how many time takes each step.
This is essentially an implementation of the answer given by Max above. For simplicity I'll represent each listening episode as a start time and length as integer values (they could be changed to actual datetimes, and then the queries would need to be modified to use date arithmetic.)
> select * from episodes;
+--------+------+
| start | len |
+--------+------+
| 50621 | 480 |
| 24145 | 546 |
| 93943 | 361 |
| 67668 | 622 |
| 64681 | 328 |
| 110786 | 411 |
...
The following query combines the start and end times with a UNION, flagging end times to distinguish from start times, and keeping a running accumulator of the number of listeners:
SET #idx=0;
SET #n=0;
SELECT (#idx := #idx + 1) as idx,
t,
(#n := #n + delta) as n
FROM
(SELECT start AS t,
1 AS delta
FROM episodes
UNION ALL
SELECT start + len AS t,
-1 AS delta FROM episodes
ORDER BY t) stage
+------+--------+------+
| idx | t | n |
+------+--------+------+
| 1 | 8 | 1 |
| 2 | 106 | 2 |
| 3 | 203 | 3 |
| 4 | 274 | 2 |
| 5 | 533 | 3 |
| 6 | 586 | 2 |
...
where 't' is the start of each interval (it's a new "interval" whenever the number of listeners, "n", changes). In a version where "t" is an actual datetime, you could easily group by day to obtain a peak episode for each day, or other such summaries. To get the end time of each interval - you could take the table above and join it to itself on right.idx = left.idx + 1 (i.e. join each row with the succeeding one).
SELECT
COUNT(*) AS listeners,
current.time_start, AS peak_start,
MIN(overlap.time_end) AS peak_end
FROM
yourTable AS current
INNER JOIN
yourTable AS overlap
ON overlap.time_start <= current.time_start
AND overlap.time_end > current.time_start
GROUP BY
current.time_start,
current.time_end
HAVING
MIN(overlap.time_end) < COALESCE((SELECT MIN(time_start) FROM yourTable WHERE timeStart > current.timeStart), current.time_end+1)
For each record, join on everything that overlaps.
The MIN() of the overlapping records' time_end is when the first current listener stops listening.
If that time is less than next occurance of a time_start, it's a peak. (Peak = start immediately followed by a stop)

MySQL, how to repeat same line x times

I have a query that outputs address order data:
SELECT ordernumber
, article_description
, article_size_description
, concat(NumberPerBox,' pieces') as contents
, NumberOrdered
FROM customerorder
WHERE customerorder.id = 1;
I would like the above line to be outputted NumberOrders (e.g. 50,000) divided by NumberPerBox e.g. 2,000 = 25 times.
Is there a SQL query that can do this, I'm not against using temporary tables to join against if that's what it takes.
I checked out the previous questions, however the nearest one:
is to be posible in mysql repeat the same result
Only gave answers that give a fixed number of rows, and I need it to be dynamic depending on the value of (NumberOrdered div NumberPerBox).
The result I want is:
Boxnr Ordernr as_description contents NumberOrdered
------+--------------+----------------+-----------+---------------
1 | CORDO1245 | Carrying bags | 2,000 pcs | 50,000
2 | CORDO1245 | Carrying bags | 2,000 pcs | 50,000
....
25 | CORDO1245 | Carrying bags | 2,000 pcs | 50,000
First, let me say that I am more familiar with SQL Server so my answer has a bit of a bias.
Second, I did not test my code sample and it should probably be used as a reference point to start from.
It would appear to me that this situation is a prime candidate for a numbers table. Simply put, it is a table (usually called "Numbers") that is nothing more than a single PK column of integers from 1 to n. Once you've used a Numbers table and aware of how it's used, you'll start finding many uses for it - such as querying for time intervals, string splitting, etc.
That said, here is my untested response to your question:
SELECT
IV.number as Boxnr
,ordernumber
,article_description
,article_size_description
,concat(NumberPerBox,' pieces') as contents
,NumberOrdered
FROM
customerorder
INNER JOIN (
SELECT
Numbers.number
,customerorder.ordernumber
,customerorder.NumberPerBox
FROM
Numbers
INNER JOIN customerorder
ON Numbers.number BETWEEN 1 AND customerorder.NumberOrdered / customerorder.NumberPerBox
WHERE
customerorder.id = 1
) AS IV
ON customerorder.ordernumber = IV.ordernumber
As I said, most of my experience is in SQL Server. I reference http://www.sqlservercentral.com/articles/Advanced+Querying/2547/ (registration required). However, there appears to be quite a few resources available when I search for "SQL numbers table".