month vs month query (data in the same table) - sql

I have the access table with the structure as bellow.
I want to do a query that will substract the VOLUME from last month (the month of the data in in SOURCE field) from the data that was inputed this month.
For the example above the result should be something like:
SOURCE | VERSION | SALES MODEL | DESTINATION | PERIOD | VOLUME |
-------+---------+-------------+-------------+--------+--------|
201309 | 1 | model 1 | eu | 201309 | -1 |
In the table I have more models, more months and more sources. I need to have the source and source-1 substraction all the time and the data should match to the model, destination and period.
So if I have 3 sources (instead of two as above) it should return the 201308-201307 and 201309-201308 results.
Is this possible in access?

You can join a table onto itself by using table aliases. Once you know this the only tricky thing is figuring out what month value comes immediately after another.
Select
t1.source,
t1.version,
t1.[sales model],
t1.destination,
t1.period,
t1.volume - t2.volume as volume
From
table t1
inner join
table t2
on
t1.Source = IIf(t2.source Mod 100 = 12, t2.Source + 89, t2.Source + 1) And
t1.version = t2.version and
t1.[sales model] = t2.[sales model] and
t1.destination = t2.destination and
t1.period = t2.period
Edit - fixed the next month test for December

Related

max DISTINCT returns multiple rows

I am working on an sql script which is executed by a .bat daily and outputs a list of IDs, the date of access, and their level.
While it returns what I want, mostly, I noticed that some of the outputted rows are duplicates.
Could someone please help me modify my script so that it outputs only one date (the latest) for each ID?
Thank you very much.
SELECT T.ID
+ ';' + substring(convert(char, convert(date , T.QDATE ) ), 1, 10)
+ ';' + A.[LEVEL]
FROM
(SELECT CID AS 'ID',
MAX (DISTINCT EDATE) QDATE
FROM [XXXXXXXXXXXXXXXXXXXXXXXX].[XXX].[XXXXXXXXXXXXXXX]
GROUP BY CID
) T ,
[XXXXXXXXXXXXXXXXXXXXXXXX].[XXX].[XXXXXXXXXXXXXXX] A
WHERE
T.ID = A.CID
AND T.QDATE = A.EDATE
ORDER BY A.[CID]
EDIT: I've added a bit of sample data from table A
| QID | CID | LEVEL | EDATE | OP | STATUS |
|-----|-----|-------|------------|----|--------|
| 1 |00001| LOW | 2021-07-16 | 01 | CLOSED |
| 2 |00001| LOW | 2021-07-16 | 01 | CLOSED |
| 3 |00002| MEDIUM| 2021-07-16 | 01 | CLOSED |
| 4 |00003| LOW | 2021-07-16 | 01 | CLOSED |
In this bit of data, my output contains both rows for CID 00001. Looking for a way to delete the duplicate rows from the output and not make any modifications to the db itself.
Your data is showing only a date portion context of your EDate field. Is is really a date or date/time. It would suggest date/time due to your call to CONVERT( Date, T.QDate) in the query. Your sample data SHOULD show context of time, such as to the second. I would not suspect there are multiple records with the same time-stamp to the second, but its your data.
The DISTINCT should not be at the inner query, but the OUTER query, but IF you have multiple entries for the same CID AT the exact same time AND there are multiple values for Leve, OP, and Status, then you will get multiple.
However, if the values are the same across-the-board as in your sample data, you SHOULD be good with
SELECT DISTINCT
T.ID + ';'
+ substring(convert(char, convert(date , T.QDATE ) ), 1, 10)
+ ';' + A.[LEVEL]
FROM
( SELECT
CID AS 'ID',
MAX (EDATE) QDATE
FROM
[XXXXXXXXXXXXXXXXXXXXXXXX].[XXX].[XXXXXXXXXXXXXXX]
GROUP BY
CID ) T
JOIN [XXXXXXXXXXXXXXXXXXXXXXXX].[XXX].[XXXXXXXXXXXXXXX] A
ON T.ID = A.CID
AND T.QDATE = A.EDATE
ORDER BY
A.CID
The distinct keyword in this context means only give me 1 unique record per each combination of all columns. So in your sample data, you would only have 1 record result for the CID = '00001'.

Compare one row of a table to every rows of a second table

I am trying to retrieve the number of days between a random date and the next known date for a holiday. Let's say my first table looks like this :
date | is_holiday | zone
9/11/18 | 0 | A
22/12/18 | 1 | A
and my holidays table looks like this
start_date | end_date | zone
20/12/18 | 04/01/18 | A
21/12/18 | 04/01/18 | B
...
I want to be able to know how many days are between an entry that is not a holiday in the first table and the next holiday date.
I have tried to get the next row with a later date in a join clause but the join isn't the tool for this task. I also have tried grouping by date and comparing the date with the next row but I can have multiple entries with the same date in the first table so it doesn't work.
This is the join clause I have tried :
SELECT mai.*, vac.start_date, datediff(vac.start_date, mai.date)
FROM (SELECT *
FROM MAIN
WHERE is_holiday = 0
) mai LEFT JOIN
(SELECT start_date, zone
FROM VACATIONS_UPDATED
ORDER BY start_date
) vac
ON mai.date < vac.start_date AND mai.zone = vac.zone
I expect to get a table looking like this :
date | is_holiday | zone | next_holiday
9/11/18 | 0 | A | 11
22/12/18 | 1 | A | 0
Any lead on how to achieve this ?
It might get messy to do it in SQL but if in case you are open to doing it from code, here is what it should look like. You basically need a crossJoin
Dataset<Row> table1 = <readData>
Dataset<Row> holidays = <readData>
//then cache the small table to get the best performance
table1.crossJoin( holidays ).filter("table1.zone == holidays.zone AND table1.date < holidays.start_date").select( "table1.*", "holidays.start_date").withColumn("nextHoliday", *calc diff*)
In scenarios where one row from table1 matches multiple holidays, then you can add an id column to table1 and then group the crossJoin.
// add unique id to the rows
table1 = table1.withColumn("id", functions.monotonically_increasing_id() )
Some details on crossJoins:
http://kirillpavlov.com/blog/2016/04/23/beyond-traditional-join-with-apache-spark/

Retrieve the Financial Year data

How to access the data from MSSQL table
User will give only month(3) and financial year(2013-14), how can I retrieve the progress up to last month (previous month) and up to month (this month) while data has been inserted from jun-2013 to march-2014
I have tried but I have given like month 3 and financial year 2013-14 but its calculate only two month data while it should be calculate Apr-2013 to Mar-2014 data
My table structure is like
+--------+-------+------+---------+
| amount | month | year | finyear |
+--------+-------+------+---------+
| 12456 | 2 | 2013 | 2013-14 |
+--------+-------+------+---------+
thanks
Something like this should do it:
SELECT SUM(a.amount) + SUM(b.amount)
FROM table a
INNER JOIN table b ON b.year = a.year - 1
WHERE a.finyear = '2013 - 14'
AND a.month <= 3
AND b.month > 3
Although your data structure and example data is pretty confusing..

Splitting one row into two rows

How do I split one row into two in SQL?
Let's say I have the columns
Name, Time, Model
and I have a row such as 'Nick', 1:00, 2010. Also Model can either be 2010 or 2012.
How can I make it such that I'll have
'Nick', NULL, 2012
'Nick', 1:00, 2010
instead of just one row. Basically, I need to do something like this for all rows in my table, where we list the model that's not listed as a new row with a NULL value under the date section.
Thanks!
SELECT name,
CASE q.id WHEN 1 THEN time END time,
CASE q.id WHEN 1 THEN model ELSE '2012' END model
FROM (
SELECT 1
UNION ALL
SELECT 2
) q (id)
CROSS JOIN
mytable
This is also working. If required, you can add more years to the value list like (2011),(2013) to get expected results for those years as well.
Fiddle example (Example data types may be different to yours)
select name,
case when t1.model = t2.year then t1.time end time,
year
from temp t1
cross join (values (2010),(2012)) as t2(year)
order by t2.year desc
| NAME | TIME | YEAR |
--------------------------
| Nick | 01:00:00 | 2010 |
| Nick | (null) | 2012 |

Summing one tables value and grouping it with a single value of another table

I have two tables.
Table 1: Actuals
A table with all the employess and how many hours they have worked in a given month
| ID | empID | hours | Month |
--------------------------------------
Table 2:
A target table which has hour target per month. The target refers to an amount that the sum of all the hours worked by the employees should meet.
| ID | hours target | Month |
-----------------------------------
Is it possible to return the sum of all table 1's hours with the target of table 2 and group it by the month and return it in a single data set?
Example
| Month | Actual Hours | hours target |
-----------------------------------------
| 1 | 320 | 350 |
etc.
Hope that is clear enough and many thanks for considering the question.
This should work:
SELECT t.[month], sum(a.[hours]) as ActualHours, t.[hourstarget]
FROM [TargetTable] t
JOIN [ActualsTable] a on t.[month] = a.[month]
GROUP BY t.[month], t.[hourstarget]
Written in plain English, you're saying "give me the sum of all hours accrued, grouped by the month (and also include the target hours for that month)".
WITH
t1 AS (SELECT mnth, targetHours FROM tblTargetHours),
t2 AS (SELECT mnth, sum(hours) AS totalhours FROM tblEmployeeHours GROUP BY mnth)
SELECT t1.mnth, t2.totalhours, t1.targethours
FROM t1, t2
WHERE t1.mnth = t2.mnth
results:
mnth totalhours targethours
1 135 350
2 154 350
3 128 350