Inserting date from Access DB into SQL Server 2008R2 - sql-server

It seemed to be an easy task but I fail and do not find a solution for my problem: I have a local table in Access 2010 with a date/time column and I want to update a column in a SQL Server table with a datatype date.
Sending the date/time values direct to the SQL Server table fails, same with converting the date/time column with this VBA function:
Function DateForSQL(dteDate) As String
DateForSQL = "'" & Format(CDate(dteDate), "yyyy-mm-dd") & "'"
End Function
which gives
DateForSQL(Date()) = '2016-01-14'
and should work, I assumed.
The update command is this:
UPDATE SQL_table
INNER JOIN local_table ON SQL_table.ID = local_table.ID
SET SQL_table.DateField = DateForSQL(local_table.DateField)
But it fails again in Access with a type conversion error.
Even when changing the SQL Server table column to datetime I get the same error.
Same with sending to SQL a string like '14/01/2016' or '01/14/2016'.
The only thing I could do - eventually - is to change the datetime to text in Access and try again, but this could not be the only solution.
Any help?
Thanks
Michael

First of all, I recommend to use the ISO-8601 format for your date - which is YYYYMMDD (no dashes, nothing) - this works for all regional & language settings in SQL Server.
Next, I'm not sure about Access' SQL syntax, but in SQL Server, your UPDATE statement would be to be something like this:
UPDATE sql
SET sql.DateField = DateForSQL(local_table.DateField)
FROM local_table local
INNER JOIN SQL_table sql ON local.ID = sql.ID
First UPDATE, then SET, then FROM and INNER JOIN ...

Related

Pass parameter from Excel to SQL in PowerQuery

I want to set local variables or pass parameters from Excel to SQL. I've found similar questions, but all referred to old versions of Excel and/or the answers showed how to filter or manipulate output from a generic SQL query in the Power Query Editor, rather than pass a parameter or modify the SQL, so that the SQL Server supplies data in the needed form.
I'm building a large Microsoft Excel spreadsheet that depends on ten different SQL queries, all against a common SQL Server database. Excel and SQL Server are installed on my laptop and are current versions (as of 16 Mar 2022). All ten queries share a common date restriction, imposed in the WHERE clauses of the queries. The tables accessed and the form of output are very different, so there is no easy way to combine the ten queries into a single query. The queries contain multiple levels of aggregation (e.g. SUM(...)) so I need to restrict the records accessed prior to aggregation and passing results from the query back to Excel.
As currently written, each query begins by setting two date values in local variables. For example,
DECLARE #BEGIN_DATE AS smalldatetime;
DECLARE #END_DATE AS smalldatetime;
#BEGIN_DATE = CAST('2021-03-01 00:00' AS smalldatetime);
#END_DATE = CAST('2021-03-02 23:59' AS smalldatetime);
Every one of the ten queries includes a line in the WHERE clause similar to
WHERE
PickUpDate BETWEEN #BEGIN_DATE AND #END_DATE
Every query will use the same pair of dates. However, the column filtered (PickUpDate above) changes from one query to the next.
As it is, I have to manually edit each of the ten queries to change the two dates--twenty edits in all. This is time-consuming and error-prone. Ideally, I'd like to set the date range in the spreadsheet, in a pop-up dialog box, or any other convenient way and pass the dates to the SQL queries. Then by selecting Data > Refresh All in Excel, update all my tables at once.
Is this possible, and if so, how does one do it?
The answer from David Browne is generally on-target. But I found some difficulties reading data from an Excel table directly into the SQL, given security restrictions in the latest version of Excel/Power Query. Also, since this was the first time I worked directly in M-code and the advanced editor, it was challenging to fill-in the gaps.
I finally got a nice solution running; here is what worked for me.
First, I stored the parameter values in a two-column table. My table is named "ParameterTable" with column headers named "Parameter_Name" and "Value". The value(s) to pass to SQL Server are stored in the Value column. My table has two rows with row entries labeled "Begin_DateTime" and "End_DateTime".
Secondly I created a callable function named “ftnGetParameter.” Select Data > Get Data > From Other Sources > Blank Query. Then select “Advanced Editor.” Delete any boilerplate added by Excel, and enter and save this function
let theParameter=(TableName,ParameterLabel) =>
let
Source=Excel.CurrentWorkbook(){[Name=TableName]}[Content],
value = Source{[Parameter_Name=ParameterLabel]}[Value]
in
value
in
theParameter
Thirdly, code-up your SQL statement as usual. I was trying to pass dates to SQL, so I initially coded with string literals. Enter the query in the usual way. I used Data > Get Data > From Database > From SQL Server Database. Then pasted in the SQL. The two relevant lines in my query looked like this:
DECLARE #BEGIN_DATE AS SMALLDATETIME='2021-01-01 00:00';
DECLARE #END_DATE AS SMALLDATETIME='2021-12-31 23:59';
You could skip this step, but it allowed me to get complex SQL code entered, formatted, and running before I invoked the function to pass the parameters.
Finally, simply replace the string literals in the SQL with code to call the function. My first few lines of M-code looks like this:
let
Source = Sql.Database("DESKTOP-04P8E8C", "nfbdata",
[Query=
"
DECLARE #BEGIN_DATE AS SMALLDATETIME= '" & ftnGetParameter("ParameterTable","Begin_DateTime") & "';
DECLARE #END_DATE AS SMALLDATETIME='" & ftnGetParameter("ParameterTable","End_DateTime") & "' (… the query continues )
Excel will issue some warnings about running the query and prompt you to edit permissions. Once permission has been granted, the function reads the text from the parameter table and passes it into the SQL.
I found that the function call was not optional. Apparently, importing the code directly into a native call to SQL Server is considered an unacceptable security risk.
Many thanks to Mr. David Browne. His post definitely points in the right direction.
You can reference a table on a sheet from Power Query and integrate values from that table into your other queries. Eg if ParameterTable is a single-row table on some worksheet with a column called "StartDate", something like
let
theDate = Date.From( Record.Field(Table.First(ParameterTable),"StartDate") ),
Source = Sql.Databases("localhost"),
AdventureWorksDW2017 = Source{[Name="AdventureWorksDW2017"]}[Data],
dbo_DimDate = AdventureWorksDW2017{[Schema="dbo",Item="DimDate"]}[Data],
#"Filtered Rows" = Table.SelectRows(dbo_DimDate, each [FullDateAlternateKey] = theDate )
in
#"Filtered Rows"
for M query folding, or
let
theDate = Date.From( Record.Field(Table.First(ParameterTable),"StartDate") ),
sql = "
select *
from dimDate
where FullDateAlternateKey = '" & Text.From(theDate) & "'
",
Source = Sql.Database("localhost", "adventureworksdw2017", [Query=sql])
in
Source
for dynamic SQL.

SSIS: Variable from SQL to Data Flow Task

Pretty new to BI and SQL in general, but a few months ago I didn't even know what a model is and now here I am...trying to build a package that runs daily.
Currently running this is Excel via PowerQuery but because the data is so much, I have to manually change the query every month. Decided to move it into SSIS.
Required outcome: Pull the last date in my Database and use it as a variable in the model (as I have millions of rows, I only want to load lines with dates greater than what I have in my table already).
Here is my Execute SQL Task:
I set up a variable for the SQL query
and trying to use it in my OLE DB query like this
Execute SQL Task: results, are fine - returns date as "dd/mm/yyyy hh24:mi:ss"
SELECT MAX (CONVACCT_CREATE_DATE) AS Expr1 FROM GOMSDailySales
Variable for OLE DB SQL Query:
"SELECT fin_booking_code, FIN_DEPT_CODE, FIN_ACCT_NO, FIN_PROD_CODE, FIN_PROG_CODE, FIN_OPEN_CODE, DEBIT_AMT, CREDIT_AMT, CURRENCY_CODE, PART_NO, FIN_DOC_NO, CREATE_DATE
FROM cuown.converted_accounts
WHERE (CREATE_DATE > TO_DATE(#[User::GetMaxDate],'yyyy/mm/dd hh24:mi:ss'))
AND (FIN_ACCT_NO LIKE '1%')"
Currently getting missing expression error, if I add " ' " to my #[User::GetMaxDate], I get a year must be between 0 and xxxx error.
What am I doing wrong / is there a cleaner way to get this done?
In the OLEDB source use the following, change the data access mode to SQL command, and use the following command:
SELECT fin_booking_code, FIN_DEPT_CODE, FIN_ACCT_NO, FIN_PROD_CODE, FIN_PROG_CODE, FIN_OPEN_CODE, DEBIT_AMT, CREDIT_AMT, CURRENCY_CODE, PART_NO, FIN_DOC_NO, CREATE_DATE
FROM cuown.converted_accounts
WHERE (CREATE_DATE > TO_DATE(?,'yyyy/mm/dd hh24:mi:ss'))
AND (FIN_ACCT_NO LIKE '1%')
And click on the parameters button and map #[User::GetMaxDate] to the first parameter.
For more information, check the following answer: Parameterized OLEDB source query
Alternative method
If parameters are not supported in the OLE DB provider you are using, create a variable of type string and evaluate this variable as the following expression:
"SELECT fin_booking_code, FIN_DEPT_CODE, FIN_ACCT_NO, FIN_PROD_CODE, FIN_PROG_CODE, FIN_OPEN_CODE, DEBIT_AMT, CREDIT_AMT, CURRENCY_CODE, PART_NO, FIN_DOC_NO, CREATE_DATE
FROM cuown.converted_accounts
WHERE CREATE_DATE > TO_DATE('" + (DT_WSTR, 50)#[User::GetMaxDate] +
"' ,'yyyy/mm/dd hh24:mi:ss') AND FIN_ACCT_NO LIKE '1%'"
Then from the OLE DB source, change the data access mode the SQL Command from variable and select the string variable you created.
Your trying to use the SSIS variable like a variable in the query. When constructing a SQL query in a string variable you simply need to concatenate the strings together. The expression for your query string variable should look like this.
"SELECT fin_booking_code, FIN_DEPT_CODE, FIN_ACCT_NO, FIN_PROD_CODE, FIN_PROG_CODE, FIN_OPEN_CODE, DEBIT_AMT, CREDIT_AMT, CURRENCY_CODE, PART_NO, FIN_DOC_NO, CREATE_DATE
FROM cuown.converted_accounts
WHERE CREATE_DATE > " + #[User::GetMaxDate] +
"AND (FIN_ACCT_NO LIKE '1%')"

VBA Access SQL Server table insert behaves differently

I have a problem when changing access code to SQL Server. I am trying to save the data in SQL Server, not in the Access database.
Access code
SELECT MAX("SPR-" & VAL(Replace([RequestID],"SPR-",""))+1) AS AutoID
FROM Tb_Request;
SQL Server:
SELECT FORMAT(MAX(1 + REPLACE(RequestID, 'SPR-', '')),'SPR-#') AS RequestNo
FROM dbo.PilotRequest
I think I changed correctly because I checked in SQL Server, the result is correct.
When I apply this code in Access, the result looks like this:
(There is data in the dbo.PilotRequest table, which is '5555'.)
Is there anyone who knows the reason for this?
You need to do the concatenation outside of the Max, else your Max will compare strings and fail (because there's a string inside it).
SELECT "SPR-" & MAX(VAL(Replace([RequestID],"SPR-",""))+1) AS AutoID
FROM Tb_Request;

Update SQL Server Table from Access Table containing Date/Time Data Type

I'm having an issue transferring some existing data from an Access Back-End Table to a SQL Server 2012 Back-End table. I'm up sizing our database, and since our Access database relies on tables from our ERP software which is also on SQL Server, it makes sense to run all queries on SQL server and just retrieve information in Access from SQL Server though ODBC.
Here is the problem. When trying to update all fields from StatusT (Access Table) to dbo_StatusT (SQL Server Table), it only works if I leave out the Date/Time data type columns. The moment I introduce the date/time data type in the update query, it says that over 13000 rows cannot be updated, but at the end it doesn't copy anything over. If I leave out the date/time fields from the query, the rest of the data transfers over easily.
ACCESS SQL Server
Field Name Data Type Column Name Data Type
OrderID Number OrderID int
LoadID Number LoadID int
StepNumber Number StepNumber smallint
InProgress Yes/No InProgress bit
Completed Yes/No Completed bit
TimeStamp Date/Time TimeStamp datetime
TimeStamp_Completed Date/Time TimeStamp_Completed datetime
As far as I can tell, my tables are set up properly on both ends, and the datetime data type in SQL Server should work with Date/Time data type in Access.
I get the following error in access when I try to move the data over from Access to SQL Server.
Microsoft Access didn't update 13243 field(s) due to a type conversion failure, 0, record(s) due to key violations, 0 record(s) due to lock violations, and 0 record(s) due to validation rule violations.
Here is my query.
UPDATE StatusT INNER JOIN dbo_StatusT ON (StatusT.StepNumber = dbo_StatusT.StepNumber) AND (StatusT.LoadID = dbo_StatusT.LoadID) AND (StatusT.OrderID = dbo_StatusT.OrderID) SET dbo_StatusT.Completed = IIf([StatusT].[Completed]=-1,1,0), dbo_StatusT.InProgress = IIf([StatusT].[InProgress]=-1,1,0), dbo_StatusT.[Timestamp] = [StatusT].[Timestamp], dbo_StatusT.Timestamp_Completed = [StatusT].[Timestamp_Completed];
I have adjusted the Yes/No fields to use 1 and 0 due to the bit representation in SQL Server, but I just can't figure out the Date/Time problem. OrderID, LoadID, and StepNumber are the fields that are both the same on each side, the rest of the data needs to update on SQL Server.
A big silly mistake on my end. I made some changes to the tables, but I never re-linked my tables in Access. Which means that it was still going off of the data types set up in the previous table configuration in MS SQL Server. The moment I refreshed the tables, everything worked without any issues. Thanks for the help.
I would suggest converting the date/time in Access to a string - perhaps MS SQL will be able to read this:
UPDATE StatusT
INNER JOIN dbo_StatusT ON (StatusT.StepNumber = dbo_StatusT.StepNumber)
AND (StatusT.LoadID = dbo_StatusT.LoadID)
AND (StatusT.OrderID = dbo_StatusT.OrderID)
SET dbo_StatusT.Completed = IIf([StatusT].[Completed]=-1,1,0),
dbo_StatusT.InProgress = IIf([StatusT].[InProgress]=-1,1,0),
dbo_StatusT.[Timestamp] = FORMAT([StatusT].[Timestamp], "yyyymmdd hh:mm:ss"),
dbo_StatusT.Timestamp_Completed = FORMAT([StatusT].[Timestamp_Completed], "yyyymmdd hh:mm:ss");

Extract table name from field in an open ADO recordset (SQL SERVER / VBA)

How can I extract the table name from a field in an open ADO recordset?
I can use the .source property to return the select statement, but if I want to know which table a field is associated with, how would I do that?
i.e. if .source returns a something like SELECT Foo, Boo, Shoo FROM table1, table2 how could I query the recordset to see which table Boo is coming from?
My data source is a SQL Server 2005 database and I'm using VBA 7.0/VBA 6.0 (runs in both)

Resources