How to use OPENROWSET in SQL Server 2012 to insert data based on the current day in a filename? - sql-server-2012

I have the below script that works, but everyday a new file is saved in the same location with the current day. Instead of having to change the script daily how can I make the script use the most current filename to insert the data automatically?
Today the filename is 6-day Plan - Daily View August 2.xlsm
tomorrow it will be 6-day Plan - Daily View August 3.xlsm
the day after tomorrow it will be 6-day Plan - Daily View August 4.xlsm and so on.
INSERT INTO [dbo].['Business SOD$']
SELECT [LOB]
,[Target]
,[Forecast]
,[Hours Required]
,[AHT]
,[Abs %]
,[OCC %]
,[Notes]
FROM OPENROWSET('Microsoft.ACE.OLEDB.12.0',
'Excel 12.0;Database=\\VF_RSOSDCNASUDA\fidopost\National_Command\National Command Centre\ncc\ntsd\syl\6-day Plan - Daily View August 2.xlsm;HDR=YES',
'SELECT * FROM [Business SOD$A4:H]')
Any help would be appreciated.
Thanks

I dabbled and came up with a solution
DECLARE #SQL varchar(max)='
SELECT [LOB]
,[Target]
,[Forecast]
,[Hours Required]
,[AHT]
,[Abs %]
,[OCC %]
,[Notes]
FROM OPENROWSET(''Microsoft.ACE.OLEDB.12.0'',
''Excel 12.0;Database=\\VF_RSOSDCNASUDA\fidopost\National_Command\National Command Centre\ncc\ntsd\syl\6-day Plan - Daily View ' + DATENAME(mm,GETDATE()) + ' ' + DATENAME(dd,GETDATE()) + '.xlsm;HDR=YES'',
''SELECT * FROM [Business SOD$A4:H]'')'
INSERT INTO [dbo.].['Business SOD$']
EXEC(#SQL)

Related

Automatically add rows based on schedule

I am currently building reports off a legacy system in SQL. The data is stored like the below.
Which I have now unpivoted, so this information is stored as a row per contract.
Here is what I am struggling to achieve, I am trying to build a payment schedule table for these contracts. The majority of them are fine as the "FirstPaymentDate" is the full payment we expect, however for some of them we receive the payment every 30 days until the contract is paid off.
So, in the example above, there is a contractvalue of 1000 and a sold term of 2 years. 1000/24 months = £41.6 per month. I need to display this as a table with each date that we expect payment up until the last date, such as the below
Not going to lie, I am struggling how to approach this. I have tried searching but not sure what labels I would search for to cover my issue.
Can anyone help with an approach to solve this? Even if it's just pointing me in the right direction?
You could do this with a recursive CTE. The code below outputs the desired result set you have shown. Your question asks for payments every 30 days but the desired result set example shows every month. This example shows a payment every month. If you need every 30 days you can update to DATEADD(DAY, 30, PaymentDate).
DROP TABLE IF EXISTS #Contract;
CREATE TABLE #Contract
(
ContractId INT
, SoldTerm INT
, FirstPaymentDate DATE
, ContractValue MONEY
, PaymentTerms INT
);
INSERT INTO #Contract VALUES (10222, 2, '01/04/2022', 1000, 30);
WITH ContractDates AS
(
SELECT ContractId, FirstPaymentDate AS PaymentDate, 1 AS Payment, (ContractValue / (SoldTerm * 12)) AS PaymentAmount, (SoldTerm * 12) AS LastPayment
FROM #Contract
UNION ALL
SELECT ContractId, DATEADD(MONTH, 1, PaymentDate), Payment + 1 AS Payment, PaymentAmount, LastPayment
FROM ContractDates
WHERE Payment + 1 <= LastPayment
)
SELECT * FROM ContractDates;
DROP TABLE IF EXISTS #Contract;

Access 2013 append query to only add new records of date is not already present

I have an access 2013 DB I’m creating. Total newbie. I have a tblHistoricalTaxes and a qryTaxes all the fields in tbl match those in qry. The fields are date, total earned, TaxRate and Tax Owed. Tax Owed is just a calculated field. When the qry runs it adds record to tblHistoricalTaxes. I’d like it so every time it runs it does not re-add records if records already exist in tblHistoricalTaxes where a record with that date is already present, Because I only need records in that table from the time they were added. If the tax rate changes in the future, I don’t need a record added for the taxes on that date with the new rate because it’s irrelevant. SQL view says
INSERT INTO tblHistoricalTaxes ( [Date], [Total Earned], TaxRate, [Tax Owed])
SELECT qryTotals.Date, qryTotals.[Total Earned], tblInfo.TaxRate, [Total Earned]*[TaxRate] AS [Tax Owed]
FROM tblInfo, qryTotals;
What do I need to change? Thank you.
Try like this:
INSERT INTO tblHistoricalTaxes ( [Date], [Total Earned], TaxRate, [Tax Owed])
SELECT qryTotals.Date, qryTotals.[Total Earned], tblInfo.TaxRate, [Total Earned]*[TaxRate] AS [Tax Owed]
FROM tblInfo, qryTotals
WHERE qryTotals.Date NOT IN ( SELECT DISTINCT [Date] FROM tblHistoricalTaxes )

SQL to bucket numbers

so i am trying to bucket business days into buckets but I am getting stuck:
IF OBJECT_ID('mattexcel2') IS NOT NULL DROP TABLE mattexcel2 PRINT ' DROP TEMP TABLE'
SELECT * INTO mattexcel2 FROM SA_MASTER_BASE PRINT ' INSERT INTO TEMP TABLE'
GO
ALTER TABLE mattexcel2 ADD [Bucket] NVARCHAR(255) PRINT 'Bucket'
GO
UPDATE mattexcel2 SET [Bucket] = '0-3 Days' where [Business days in current Status] <= 3
GO
When I run this in SQL I get:
Conversion failed when converting the nvarchar value '1.91' to data
type int.
So I want 1.9 to fall under my Bucket column as 0-3 Days.
As mentioned in the comments, the problem is:
[Business days in current Status] <= 3
Because [Business days in current Status] is a string, it needs to be converted to a number for the comparison. SQL Server chooses an integer. You can fix this by using a decimal place:
UPDATE mattexcel2
SET [Bucket] = '0-3 Days'
WHERE try_convert(decimal(38, 4), [Business days in current Status]) <= 3.0;
However, I would suggest that you use a computed column:
alter table mattexcel2
add bd_bucket as (case when try_convert(decimal(38, 4), [Business days in current Status]) <= 3.0
then '0-3 Days'
end);
A computed column will always have the right value, without being updated.

Calculating a value difference between a transactions and its prior transaction

I am using MS SQL and need some advice on how to construct a query. Essentially I have file of fuel transactions (credit card swipes) and within it the current odometer reading is captured. I am trying to construct a query using the vehicle number (unique id for the vehicle), the transaction date, and the current odometer reading to calculate a new column that looks at a given fuel transaction, finds the prior transaction (based on transaction date) for that vehicle transaction and then calculates the miles that were driven between the two data points.
I am struggling with identifying the prior transaction. Any help would be appreciated to help me get started. I am not looking for the specific script, but just some pseudo code would help get me going.
If you want to get specific, here are the key columns. CompanyVehicleNumber, TransactionDate(format YYYYMMDD), TransactionTime(format HHMMSS), Odometer (e.g. 123456)
Thanks.
You can use APPLY to get the previous transaction:
SELECT
t.*, MilesDiff = t.odometer - x.odometer
FROM tbl t
OUTER APPLY(
SELECT TOP 1 odometer
FROM tbl
WHERE
CompanyVehicleNumber = t.CompanyVehicleNumber
AND (TransactionDate + TransactionTime) < (t.TransactionDate + t.TransactionTime)
ORDER BY (TransactionDate + TransactionTime) DESC
) x(odometer)
Note here that you need to convert the TransactionDate and TransactionTime to a DATETIME to be able to compare the transactions.
Here is one way to convert dates and times:
DECLARE #date VARCHAR(8) = '20130101'
DECLARE #time VARCHAR(6) = '053000'
SELECT
CAST(#date AS DATETIME) +
CAST(LEFT(#time, 2) + ':' + SUBSTRING(#time, 3, 2) + ':' + RIGHT(#time, 2) AS DATETIME)

How can I display actuals and forecasts in the same period in a report without it getting silly?

So I have a system where users can forecast up until the 18th day following the end of a month. However, during the month they are entering actuals on a day to day basis.
So say the current date is 12th September 2012. I have a forecast for this month of 100 units and I already have actuals entered into the system of 25 units.
Because the 18th October hasn't been reached I would report September as having a forecast figure of 100 units. However, the users want to also be able to see the 25 units that they have entered to date.
I have two measures in my report, one for Actuals and one for Forecasts. If I allow the actuals for September to appear in the report then I will be displaying a figure of 125 units which is obviously incorrect and will make my year total also incorrect.
I considered adding a new measure "Transient Actuals", that would only be used in the current month and wouldn't accumulate, but this seems crazy!
I don't think the technologies really matter at all but I am using a SQL Server database and the report is an Analysis Services cube.
Surely this must be a common problem?
Okay - I do have a schema but it is very, very complicated and there are multiple layers between the report and the database tables. However, I can give you a simple SQL example.
--Actuals and Forecast Tables
DECLARE #Actuals TABLE (
[Month] INT,
Value NUMERIC(19,2));
DECLARE #Forecast TABLE (
[Month] INT,
Value NUMERIC(19,2));
--Pretending we are in Month #3 put in some dummy data
INSERT INTO #Actuals VALUES (1, 100);
INSERT INTO #Actuals VALUES (2, 120);
INSERT INTO #Actuals VALUES (3, 10);
INSERT INTO #Forecast VALUES (1, 90);
INSERT INTO #Forecast VALUES (2, 90);
INSERT INTO #Forecast VALUES (3, 90);
--Calculate the latest actuals period (this would usually be time-based)
DECLARE #LatestActualsPeriod INT = 2;
--Now report the data to the user
SELECT
[Month],
'Actuals' AS Source,
Value
FROM
#Actuals
WHERE
[Month] <= #LatestActualsPeriod
UNION ALL
SELECT
[Month],
'Forecast',
Value
FROM
#Forecast
WHERE
[Month] > #LatestActualsPeriod;
Now the results of that will be a table with the following data:
Month Source Value
1 Actuals 100.00
2 Actuals 120.00
3 Forecast 90.00
So where do I put the 10.00 actuals in Month 3 without making the totals incorrect and still displaying the forecast for the same month somewhere?
Okay, thanks to Jeremy I think I have the answer... the problem is that I have data like this in my report:
Row Labels Actual Forecast Total
2012 23.840 18.840 42.680
2012/Jan 3.580 0.000 3.580
2012/Feb 3.520 0.000 3.520
2012/Mar 4.000 0.000 4.000
2012/Apr 3.350 0.000 3.350
2012/May 3.440 0.000 3.440
2012/Jun 3.090 0.000 3.090
2012/Jul 2.860 0.000 2.860
2012/Aug 0.000 4.990 4.990
2012/Sep 0.000 3.500 3.500
2012/Oct 0.000 4.130 4.130
2012/Nov 0.000 2.710 2.710
2012/Dec 0.000 3.510 3.510
Grand Total 23.840 18.840 42.680
This is an Analysis Services cube so I can't have anything like "90 Actual/ 10 Forecast" displaying, each cell must contain a number. However, I have another solution. If I add a new dimension with two members I can use this to control what is displayed.
So the new dimension will have two choices, "Show All" or "Show Relevant" (I might need to work on the names). If the user has the "Show All" member selected then they will see any Actuals and Forecasts that the system holds. So this means that their total will be meaningless as it will include forecasts AND actuals for months up to and including the present month and just forecasts for future months.
However, if the user selects the "Show Relevant" member then they will only see the Actuals for months that haven't been completed and forecasts for future months (as shown above).
This will mean that every report will need to include this dimension and force the users to pick one of the members or their figures will be totally meaningless so it isn't the most elegant solution.
I'm making a bunch of assumptions here, but hopefully this will be useful here. I took your query and am showing you some other ways to do it that I think could help in your problem of showing the data in an easier to read way, if I'm understanding the problem correctly.
In the first example I'm making the assumption that you always put the date as the first of the month. If not then it could get a little trickier, or you could use DATEPART(MONTH, ... to make it work similarly as if you were storing it as an INT. I'm not assuming that every month will have a forecasted value or an actual value.
In the second example, to make it easier, I assumed that you want to show only the actuals up to the latest month with actuals. I then assume that you want the forecasted value and actuals (if there are any) for that month and beyond. I'm also assuming that there is a forecasted value for each month in the second query.
If any of these assumptions are incorrect, then the query can be modified further to handle that.
--Actuals and Forecast Tables
DECLARE #Actuals TABLE (
[Month] DATE,
Value NUMERIC(19,2));
DECLARE #Forecast TABLE (
[Month] DATE,
Value NUMERIC(19,2));
INSERT INTO #Actuals VALUES ('20120801', 100);
INSERT INTO #Actuals VALUES ('20120901', 120);
INSERT INTO #Actuals VALUES ('20121001', 10);
INSERT INTO #Forecast VALUES ('20120801', 90);
INSERT INTO #Forecast VALUES ('20120901', 90);
INSERT INTO #Forecast VALUES ('20121001', 90);
INSERT INTO #Actuals VALUES ('20121101', 50);
INSERT INTO #Forecast VALUES ('20121201', 90);
-- If you can't have an actuals record without a forcast record, remove all the ISNULL'ing except the first ISNULL on the [Actual/Forecast] line
-- and change to LEFT JOIN instead of FULL.
SELECT
SUBSTRING(CONVERT(VARCHAR, ISNULL(F.[Month], A.[Month]), 103), 4, 999) [Report Month]
, ISNULL(CAST(A.Value AS VARCHAR(20)), '-') + '/' + ISNULL(CAST(F.Value AS VARCHAR(20)), '-') [Actual/Forecast]
FROM
#Forecast F
FULL JOIN #Actuals A
ON A.[Month] = F.[Month]
ORDER BY
[Report Month]
DELETE #Actuals
WHERE [Month] = '20121101'
DELETE #Forecast
WHERE [Month] = '20121201'
DECLARE #LatestActualsPeriod DATE = (SELECT MAX([Month]) FROM #Actuals);
SELECT
[Month] [Report Month]
, CAST(A.Value AS VARCHAR(20)) + ' Actual' [Units]
FROM
#Actuals A
WHERE
A.[Month] < #LatestActualsPeriod
UNION
SELECT
F.[Month] [Report Month]
, ISNULL(CAST(A.Value AS VARCHAR(20)), '-') + '/' + CAST(F.Value AS VARCHAR(20)) + ' Actual/Forecasted'
FROM
#Forecast F
LEFT JOIN #Actuals A
ON A.[Month] = F.[Month]
WHERE
F.[Month] >= #LatestActualsPeriod
P.S.: You put a schema in your answer, but didn't reply to my comment asking for it. If I hadn't looked back at the question again out of curiosity, I wouldn't have know you edited your question.