How to find the first column in an ACCESS table row with a value not Zero of Blank? - sql

I have a table which includes a column of each month (Jan-13, Feb-13, Mar-13, etc) for a period of four years. I need to find the first column in each row that has a value other than "0" (zero). Then I will need to find the last column with a value other than zero.
The query will let me know the start month and the end month of a resource. I have written an Excel formula but now I need to convert the same functionality to Access. When I find each of the columns I need to retrieve the column heading. Could anyone help me with the SQL for my query?
The report based on the query would be
ResourceName, StartDate EndDate
Bob Sample Apr-13 Apr-15
There are actual two tables involved. The Resource table with all the information for the individuals and a forecast table which has the months as columns and the resource id and task for rows. For each month an individual is forecast to work a given percent of their time. We are not concerned about the actual dates (11/20/201) the individual starts, just the month. So a resource for task 1 is forecast to work .5 percent of their time in Nov-13, which would be the first month that the resource work. Then that resource may be forecast to work at the same level for the next nine months. So the column for Aug-14 would be the last month with the .5 value. After that all columns contains zeros.

(I will limit my example to six months because I'm lazy.)
So we have some "wide" data in a table named [Forecast]:
ResourceID Jul-13 Aug-13 Sep-13 Oct-13 Nov-13 Dec-13
---------- ------ ------ ------ ------ ------ ------
1 0 0.5 1 0.5 0 0
2 0 0 2 0 0 0
3 0 0 3 4 0 0
Start by creating a saved query in Access named [ForecastUnpivoted] to convert the "short wide" data into "long skinny" data:
SELECT ResourceID, "2013-07" AS forecastMonth, [Jul-13] AS forecastValue
FROM Forecast
UNION ALL
SELECT ResourceID, "2013-08" AS forecastMonth, [Aug-13] AS forecastValue
FROM Forecast
UNION ALL
SELECT ResourceID, "2013-09" AS forecastMonth, [Sep-13] AS forecastValue
FROM Forecast
UNION ALL
SELECT ResourceID, "2013-10" AS forecastMonth, [Oct-13] AS forecastValue
FROM Forecast
UNION ALL
SELECT ResourceID, "2013-11" AS forecastMonth, [Nov-13] AS forecastValue
FROM Forecast
UNION ALL
SELECT ResourceID, "2013-12" AS forecastMonth, [Dec-13] AS forecastValue
FROM Forecast
which returns
ResourceID forecastMonth forecastValue
---------- ------------- -------------
1 2013-07 0
2 2013-07 0
3 2013-07 0
1 2013-08 0.5
2 2013-08 0
3 2013-08 0
1 2013-09 1
2 2013-09 2
3 2013-09 3
1 2013-10 0.5
2 2013-10 0
3 2013-10 4
1 2013-11 0
2 2013-11 0
3 2013-11 0
1 2013-12 0
2 2013-12 0
3 2013-12 0
Now we can use Min() and Max() to give us the start end end dates for each resource
SELECT
ResourceID,
Min(forecastMonth) AS StartMonth,
Max(forecastMonth) AS EndMonth
FROM ForecastUnpivoted
WHERE forecastValue <> 0
GROUP BY ResourceID
That gives us
ResourceID StartMonth EndMonth
---------- ---------- --------
1 2013-08 2013-10
2 2013-09 2013-09
3 2013-09 2013-10

In a relational database, you would not store your data like this. Instead, you would have 2 tables:
Your resources
The months in which a resource does work (for a task)
Example:
Table 1 resources:
ID | Resource_Name
1 | Mr. A
2 | Mrs. B
Table 2 Forecast:
FC_ID | FC_Month | FC_Resource_ID | FC_Task | FC_Percentage
1 | 2013-10-01 | 1 | actiontask! | 0.05
2 | 2013-11-01 | 1 | actiontask! | 0.10
3 | 2013-12-01 | 1 | actiontask! | 0.05
4 | 2013-07-01 | 2 | boring task | 0.3
5 | 2013-08-01 | 2 | boring task | 0.25
6 | 2013-09-01 | 2 | boring task | 0.3
7 | 2013-10-01 | 2 | boring task | 0.1
You can then request the start and end date using SQL:
SELECT Resource_Name, Min(FC_Month) AS colMin, Max(FC_Month) As colMax
FROM tblForecast INNER JOIN tblResources ON FC_Resource_ID=Resource_ID
GROUP BY FC_Resource_ID, Resource_Name
The result of this example will be:
Mr. A | 2013-10-01 | 2013-12-01
Mrs. B | 2013-07-01 | 2013-10-01

Related

Creating a new calculated column in SQL

Is there a way to find the solution so that I need for 2 days, there are 2 UD's because there are June 24 2 times and for the rest there are single days.
I am showing the expected output here:
Primary key UD Date
-------------------------------------------
1 123 2015-06-24 00:00:00.000
6 456 2015-06-24 00:00:00.000
2 123 2015-06-25 00:00:00.000
3 658 2015-06-26 00:00:00.000
4 598 2015-06-27 00:00:00.000
5 156 2015-06-28 00:00:00.000
No of times Number of days
-----------------------------
4 1
2 2
The logic is 4 users are there who used the application on 1 day and there are 2 userd who used the application on 2 days
You can use two levels of aggregation:
select cnt, count(*)
from (select date, count(*) as cnt
from t
group by date
) d
group by cnt
order by cnt desc;

Insert multiple rows from result of Average by date and id

I have a table with 1 result per day like this :
id | item_id | date | amount
-------------------------------------
1 1 2019-01-01 1
2 1 2019-01-02 2
3 1 2019-01-03 3
4 1 2019-01-04 4
5 1 2019-01-05 5
6 2 2019-01-01 1
7 2 2019-01-01 2
8 2 2019-01-01 3
9 2 2019-01-01 4
10 2 2019-01-01 5
11 3 2019-01-01 1
12 3 2019-01-01 2
13 3 2019-01-01 3
14 3 2019-01-01 4
15 3 2019-01-01 5
First I was trying to average the column amount for each day.
SELECT
x.item_id AS id,avg(x.amount) AS result
FROM
(SELECT
il.item_id, il.amount,
ROW_NUMBER() OVER (PARTITION BY il.item_id ORDER BY il.date DESC) rn
FROM
item_prices il) x
WHERE
x.rn BETWEEN 1 AND 50
GROUP BY
x.item_id
The result is going to be the following if calculated on 2019-01-05
item_id | average
1 3
2 3
3 3
or, if calculated 2019-01-04
item_id | average
1 2.5
2 2.5
3 2.5
My goal is to run the Average query , every day that would update the average automatically and insert it in 5th column "average" :
id | item_id | date | amount | average
5 1 2019-01-05 5 3
10 2 2019-01-05 5 3
15 3 2019-01-05 5 3
Issue is that every example i can find with Insert the Select they only update one row and they are over another table there is also the most recent date issue...
Can someone point me in the right direction?
Perhaps you want to see running average every day. Storing the value as a separate column is bound to cause problems especially when the rows are updated/deleted, the column also needs to be updated and hence will require complex triggers.
Simply create a View and run whenever you want to check the average directly from that View.
CREATE OR REPLACE VIEW v_item_prices AS
SELECT t.*,avg(t.amount) OVER ( PARTITION BY item_id order by date)
AS average FROM item_prices t
order by item_id,date
DEMO

Getting a count by date based on the number of observations with encompassing date ranges

I am working with a table in Microsoft Access whereby I have 2 columns with a start and end date.
I want to get the count by date of the number of rows with date ranges that encompass the date in the output table.
Input Data
Start Date End Date
01/02/2017 03/02/2017
07/02/2017 19/02/2017
09/02/2017 19/02/2017
11/02/2017 12/02/2017
12/02/2017 17/02/2017
Desired Output
Date Count
01/02/2017 1
02/02/2017 1
03/02/2017 1
04/02/2017 0
05/02/2017 0
06/02/2017 0
07/02/2017 1
08/02/2017 1
09/02/2017 2
10/02/2017 2
11/02/2017 3
12/02/2017 4
13/02/2017 3
14/02/2017 3
15/02/2017 3
16/02/2017 3
17/02/2017 3
18/02/2017 2
19/02/2017 2
20/02/2017 0
For this project, I have to use Microsoft Access 2010, so a solution in either SQL code or design view input would be great.
Any help on this would be appreciated. Thanks!
Use the below query to get the required result. You can also change the column with respect to your requirements
SELECT END_DATE AS DATE, COUNT(*) AS COUNT FROM TABLE_NAME
GROUP BY END_DATE ORDER BY END_DATE;

sql Query on effective date

I would like to get report for drink purchased in whole month but price of the drink can change any time in month and I would like to get report for a month with price change
I have two tables
SELECT [ID]
,[DrinkID]
,[UserID]
,[qty]
,[DateTaken]
FROM [Snacks].[dbo].[DrinkHistory]
SELECT [ID]
,[DrinkID]
,[UserID]
,[qty]
,[DateTaken]
FROM [Snacks].[dbo].[DrinkHistory]
[DrinkHistory]:
ID DrinkID UserID qty DateTaken
----------------------------------------------------------------------
1 1 1 1 2014-05-10
2 1 1 2 2014-05-15
3 2 1 1 2014-06-01
4 2 1 4 2014-06-01
5 1 1 3 2014-05-20
6 1 1 4 2014-05-30
[DrinkPricesEffect]:
PriceID DrinkID DrinkPrice PriceEffectiveDate IsCurrent
-----------------------------------------------------------------------------------
1 1 10.00 2014-05-01 1
2 1 20.00 2014-05-20 1
3 2 9.00 2014-06-01 1
4 2 8.00 2014-01-01 1
5 1 30.00 2014-05-25 1
6 1 40.00 2014-05-28 1
I would like to have result as under date taken between 2014-05-1 to 2014-05-31
DrinkId Qty Price DateTaken PriceEffectiveDate
-----------------------------------------------------------------------
1 1 10 2014-05-10 2014-05-01
1 2 10 2014-05-15 2014-05-01
1 3 20 2014-05-20 2014-05-20
1 4 40 2014-05-30 2014-05-28
Is there any who can give me some idea or write query for me?
If your drink price can change any time in a month you could additionaly save the price for each purchase. I would add a column [PricePaid] to the table [DrinkHistory].
When adding a record to [DrinkHistory], the price for the drink at the moment is known, but later it might change so you save the current price to the history...
Then for your result you could just display the Whole [DrinkHistory]
SELECT * FROM DrinkHistory;
This should work:
Select
DH.DrinkId,
DH.Qty,
DPE.DrinkPrice AS Price,
DH.DateTaken,
DPE.PriceEffectiveDate
FROM DrinkHistory DH
JOIN DrinkPricesEffect DPE ON DPE.PriceID =
(
Select Top 1 PriceID FROM
(
Select PriceID,RANK() OVER(ORDER BY PriceEffectiveDate DESC ) AS rnk
FROM DrinkPricesEffect
WHERE DH.DrinkId = DrinkId AND
DH.DateTaken >= PriceEffectiveDate
)SubQ WHERE rnk = 1
)
WHERE DH.DateTaken Between '2014-05-01' AND '2014-05-30'
Here you can find the SQL Fiddle link: http://sqlfiddle.com/#!6/5f8fb/26/0

Access SQL - Get last available value

scenario:
Table 1 (dates)
01/01/12
02/01/12
Table 2 (counts)
01/01/12 | Item 1 | 10
01/01/12 | Item 2 | 15
03/01/12 | Item 1 | 5
I have to join the two tables, not leaving gaps in dates:
An OUTER JOIN did the trick.
I want to have the last available number if that date is missing in Table 2.
E.g.
02/01/12 | Item 1 | 10
02/01/12 | Item 2 | 15
I am struggling on this. Any hints?
A query can transform, and join data, but it cannot generate new data (rows) that were not there to begin with. In your case if the 02/01/12 data row is missing you aren't going to be able to create rows on the fly to fill in the gaps in your query results.
To fix, create a 3rd table or sub-query that contains all of the lookup date segments that you need in your results, and include that in your outer join on the outer query.
Okay, so we have [Table1]
Date
----------
2013-01-01
2013-02-01
2013-03-01
and [Table2]
Date Item Qty
---------- ------ ---
2013-01-01 Item 1 10
2013-01-01 Item 2 15
2013-03-01 Item 1 5
We can start by creating a saved query in Access named [DesiredRows] to give us the complete set of Date/Item values we want to see:
SELECT Table1.Date, i.Item
FROM
Table1,
(SELECT DISTINCT Item FROM Table2) AS i
...returning
Date Item
---------- ------
2013-01-01 Item 1
2013-02-01 Item 1
2013-03-01 Item 1
2013-01-01 Item 2
2013-02-01 Item 2
2013-03-01 Item 2
Now we can use that query as part of a saved query named [LastAvailableDates] to give us the last available date in Table2 for each of those pairs
SELECT
DesiredRows.Date,
DesiredRows.Item,
MAX(Table2.Date) AS LastAvailableDate
FROM
DesiredRows
INNER JOIN
Table2
ON Table2.Item = DesiredRows.Item
AND Table2.Date <= DesiredRows.Date
GROUP BY DesiredRows.Date, DesiredRows.Item
...returning
Date Item LastAvailableDate
---------- ------ -----------------
2013-01-01 Item 1 2013-01-01
2013-01-01 Item 2 2013-01-01
2013-02-01 Item 1 2013-01-01
2013-02-01 Item 2 2013-01-01
2013-03-01 Item 1 2013-03-01
2013-03-01 Item 2 2013-01-01
Finally, we can use that query in a query to retrieve the final results
SELECT
LastAvailableDates.Date,
LastAvailableDates.Item,
Table2.Qty
FROM
LastAvailableDates
INNER JOIN
Table2
ON Table2.Date = LastAvailableDates.LastAvailableDate
AND Table2.Item = LastAvailableDates.Item
...returning
Date Item Qty
---------- ------ ---
2013-01-01 Item 1 10
2013-01-01 Item 2 15
2013-02-01 Item 1 10
2013-02-01 Item 2 15
2013-03-01 Item 1 5
2013-03-01 Item 2 15