How to migrate Access queries to SQL views? - sql-server

I am using SQL Server Migration Assistant to create linked tables to link from Access to SQL server. During the migration process I also selected Access queries along with the tables to be migrated. The tables are now migrated and linked. There was no option to link queries automatically. However, out of my 15 queries only 5 of them have migrated. SSMA docs says that:
Most SELECT queries are converted to views. Other queries, such as
UPDATE queries, are not migrated.
SELECT queries that take parameters are not converted, nor are
cross-tab queries.
When converting Access Queries to SQL Views, what would be the best course of action as it is not done automatically? I know that views need to be in T-SQL.

I helped to develop a website that will convert an Access SQL query into T-SQL. Paste in your Access SQL and it will convert and format the result as T-SQL. Test the resulting query in SSMS or an Access pass-through query.
https://accessusergroups.org/sql-converter/
The website applies over 80 conversions to the pasted in query. It can handle a lot of syntax that is specific to Access.
SELECT Instr("Please send feedback & share with friends","e") as Last_E
,DATE() AS Today_Date
,NOW() AS Today_Now
,CDate(DateUpdate) AS DateUpdate_CDate
,CCur([flags]) AS Flags_CCur
,NZ([LV], "LV NULL") AS LV_NZ
,CInt([Type]) AS Type_CInt
,CSng([MsysObjects.DateCreate]) AS DateCreate_CSng
,CDbl([MsysObjects].[DateCreate]) AS DateCreate_CDbl
,TRIM(SPACE(20) & NAME & " ") AS Name_Trim
,LEFT(NAME, 4) AS Name_Left4
,RIGHT(NAME, 4) AS Name_Right4
,MID(NAME, 4,5) AS Name_Mid45
,NOT INSTR(1, NAME, "q") <> 0 AS Name_Contains_q
,IIF(Type = 5, "Query", "Other") AS Type_IIF
,IIF(ISNULL(LvProp), "N/A", LvProp) AS LvProp_Handler
,"Amy's code IS righteous." AS SingleQuotes
,"Al's ""new"" cars" AS DoubleQuotes
,"10 + 10 = "& CStr(10 * 2) AS IgnoreMathSymbols
,DCOUNT("Name","MsysObjects","Name like Q*") as RowCount
FROM MsysObjects
WHERE [NAME] LIKE "*e*"
AND RIGHT(DATE(), 4) = 1010 * 2 + 1
The Access query above will convert to T-SQL as the following. Keep in mind that the MsysObjects table doesn't exist in SQL Server.
SELECT CHARINDEX('e', 'Please send feedback & share with friends' ) as Last_E
,CONVERT(date, GETDATE()) AS Today_Date
,GETDATE() AS Today_Now
,CONVERT(date,DateUpdate) AS DateUpdate_CDate
,CONVERT(money,[flags]) AS Flags_CCur
,ISNULL([LV], 'LV NULL') AS LV_NZ
,CONVERT(int,[Type]) AS Type_CInt
,CONVERT(real,[MsysObjects].[DateCreate]) AS DateCreate_CSng
,CONVERT(real,[MsysObjects].[DateCreate]) AS DateCreate_CDbl
,TRIM(SPACE(20) + NAME + ' ') AS Name_Trim
,LEFT(NAME, 4) AS Name_Left4
,RIGHT(NAME, 4) AS Name_Right4
,SUBSTRING(NAME, 4,5) AS Name_Mid45
,NOT CHARINDEX('q', NAME ,1) <> 0 AS Name_Contains_q
,IIF(Type = 5, 'Query', 'Other') AS Type_IIF
,IIF((LvProp IS NULL) , 'N/A', LvProp) AS LvProp_Handler
,'Amy''s code IS righteous.' AS SingleQuotes
,'Al''s "new" cars' AS DoubleQuotes
,'10 + 10 = '+ CStr(10 * 2) AS IgnoreMathSymbols
,
/* DCOUNT beta conversion */ (
SELECT COUNT(Name)
FROM MsysObjects
WHERE Name LIKE Q%
) as RowCount
FROM MsysObjects
WHERE [NAME] LIKE '%e%'
AND RIGHT(CONVERT(date, GETDATE()) , 4) = 1010 * 2 + 1

As a general rule when migrating to sql server, the select queries on the access client side SHOULD NOT be migrated to sql server. As you noted, ONLY select quires can be migrated, and worse is those views will become read only when linked. (Unless you select a PK during the migration process)
After you migrate the data, and link to those tables, then ALL OF you existing Access queries will continue to work as before.
Those Access saved queries will continue to work as before, and they are now working + using the linked tables. Most access quires do not need to be converted, and they will perform rather well without being converted.
The only exception is those complex queries with say group-by, or complex joins should be converted.
And access client quires in most cases will NOT pull the whole sql server table, so once again, little or no benefit occurs by migrating the access client side queries. I would not migrate them.
So if we have
Select * from tblInvoies where InvoiceNum = 1234
The above does NOT need to be converted to t-sql, nor does it need to be converted to a view. Converting such select quires in access to a sql view will likely introduce bugs and issues into your application.
And as noted, sql server cannot “prompt” you like Access queries can.
You only need or want to covert an access query to a sql view for those queries that are running slow.
I would not migrate ANY access queries to sql server. You are far better off to continue to use the saved Access queries client side. Most of them will not see improved performance by converting to t-sql views.
And you potential introduce a large number of bugs, and issues that will break your application.
Migrate the data tables only. Get the client application working ASAP, and then consider tweaking or migrating some of the access queries that don’t perform well. In a application with say 200 client queries, I find that only 5-10 need to be converted to views.

SQL Server definitely supports Pivots; you'll have to re-crate cross-tabs as Pivots. SQL Server definitely supports parameter queries. Just re-write the SQL. Depending on how complex the queries are, you could perhaps just copy the SQL from Access and paste it into SQL Server. You son't really save queries in SQL Server (although you could export them), but you run queries as Stored Procedures. It takes a bit of getting used to, but once you make the switch away from Access, I'm pretty sure you'll never go back.

Related

OPENDATASOURCE (Transact-SQL) - Connecting to multiple tables

I have a use case for OPENDATASROUCE. However, my SQL query has multiple tables with left joins.
Most of the examples have one table only. How I connect in case I have 2 tables (2nd table has left join)
Below is a typical example and working great:
SELECT *
FROM OPENDATASOURCE('SQLNCLI', 'Data Source=RemoteServerName;Integrated Security=SSPI').Billing.dbo.Invoices
But I need to join invoices table with 'customer' table like below. I am not sure how I do that?? Please help
SELECT *
FROM OPENDATASOURCE('SQLNCLI', 'Data Source=RemoteServerName;Integrated Security=SSPI').Billing.dbo.Invoices as inv
left join Billing.dbo.customers as cust
on inv.customer = cust.customer
OPENDATASOURCE is one way to talk to a remote server using the "linked server" or "distributed query" functionality in SQL Server. However, it is not likely the best path for you to use in this case as it does not allow for the SQL Server Query Optimizer to rewrite the query and push parts of the query down to the remote source (potentially reducing the number of rows returned to you over a slower network connection vs. your local database). If possible, creating an actual linked server would help you here. This would give you the option to say to the optimizer "these two tables are from the same remote source". Then the optimizer can consider plans that remotes a single query to the remote server that joins those two tables together, applies any filters and group by clauses, and then returns the result to the calling server.
Here's the mechanism to add a linked server:
https://learn.microsoft.com/en-us/sql/relational-databases/system-stored-procedures/sp-addlinkedserver-transact-sql?view=sql-server-2017
Once you have a remote server (which I'll call "remote" here), you can write the query using the 4-part name syntax for remote servers instead of using OPENDATASOURCE.
SELECT * FROM REMOTE.Billing.DBO.Invoices LEFT JOIN REMOTE.Billing.DBO.Invoices on <join condition> <WHERE clause>
Here is a paper on how linked servers work under the covers which should give you a conceptual overview as to why this approach is likely better for you:
http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.59.8007
Best of luck!

How to get multiple SQL Tables structure (T-SQL) into excel sheet?

I have to take 198 SQL Tables structures. Normally, I know about SP_HELP and ALT+F1 to get single table structure.
How can i get structure multiple tables? If i provide list of table names, output should be structure(Table name(field name, Data type, Length)) of all those tables.
I have only read access to SQL DB.
And, I am new to SQL.
Environment details:
Client Tool: Microsoft SQL Server Management Studio 2014
I have searched in SO, there are answers for single table. But, that doesn't solve my question.
This query will return a list of all tables and their columns with a lot of details about data_type, size, nullability and so on:
USE YourDatabaseNameHere;
SELECT t.TABLE_TYPE, c.*
FROM INFORMATION_SCHEMA.TABLES t
INNER JOIN INFORMATION_SCHEMA.COLUMNS c ON t.TABLE_SCHEMA=c.TABLE_SCHEMA
AND t.TABLE_NAME=c.TABLE_NAME
WHERE t.TABLE_TYPE = 'BASE TABLE'; --With 'VIEW' you'd find views, or just omit the WHERE...
You can use a simple Excel to connect to the database and read this result into a Sheet.
UPDATE
Did not read, that you can use SSMS. Just paste the query into a new query window and execute it. The result can be copy-pasted into excel...
I suggest to use DB Schema tool, which is used to design the database and understand the existing relational database mapping.
By using SQL Server 2008 R2
This will create a script for you then you will be able to run it on other sql server it will create the same Data Base with all talbes.
Right Click On Data Base Name
Go to Task
Go to Generate
Scripts SQL Server 2008 R2 DataBase Image
Next > Next > Next > SetYourPath Next > Finish
first Pic second Pic 3rd Pic 4th Pic 5th Pic

SSIS package Query Optimization

I would like to have idea on how to fix a minor bug identified in the program that transfers data between an Oracle Database and a SQL server Database for a web ordering systems that I support.
The issue is, when two orders are place for instance 129 and 130 on the same day, if the subsequent order (130) gets verified first, the previous web order (129) does not get moved over to the Oracle DB. This happens because that program checks for the maximum web order transferred to Oracle DB and tries to move only SQL web order numbers higher than that.
The queries built that support this concept in the SSIS package are the following:
On the Oracle Side
Select nvl(max(web_order_id),0) maxOrderIDParam from web_shipping
On the SQL Server side
SELECT cast(web_order_id as float) web_order_id, web_entry_date, site_num, protocol_num, inv_num, cast(pharm_num as float) pharm_num, status, comments, username, porstatus
FROM Web_Shipping
WHERE web_order_id > ?
AND status = 'V'
ORDER BY web_order_id
On the Oracle side
insert into web_shipping (web_order_id, web_entry_date, site_num, protocol_num, inv_num, pharm_num, status, comments, username, porStatus)
values (:web_order_id, :web_entry_date, :site_num, :protocol_num, :inv_num, :pharm_num, :status, :comments, :username, :porStatus)
On the SQL Server side
select cast(web_order_id as float) web_order_id, line_id, cast(no_of_participants as float) no_of_participants, cast(amt_inventory as float) amt_inventory, cast(NSC_num as float) NSC_num, cast(dose_str as float) dose_str, dose_unit, dose_form, dose_mult, cast(amt_req as float) amt_req
FROM web_ship_detail
WHERE web_order_id = ?
and finally on the Oracle side
insert into web_ship_detail (web_order_id, line_id, no_of_participants, amt_inventory, NSC_num, dose_str, dose_unit, dose_form, dose_mult, amt_req)
values (:web_order_id, :line_id, :no_of_participants, :amt_inventory, :NSC_num, :dose_str, :dose_unit, :dose_form, :dose_mult, :amt_req)
The effort has been to devise a resolution with minimum code change in the whole SSIS package.
I know you are looking for minimal code change not sure if these qualify but will 100% fix the problem. There are 3 options:
Modify the MS SQL table and include a "IsTransferred" bit column. When the verified record is moved to oracle, update the column to a 1/true
Keep track separate table of orders that have been transferred to Oracle. When selecting MS SQL orders exclude those that exist in the new "transferred" table.
Create a Data Flow object, with the Oracle & MS SQL orders tables as sources, use a Merge Join, using left outer. Use the results where Oracle columns are null (there is no matching Oracle records, didn't transfer) and use those records to transfer over to Oracle.
No Idea how many records are on both sides, so there may be performance concerns for some of the options.

Is it possible to connect an Access form to a SQL Server view

I'm migrating an Access DB to SQL Server and everything is slowly coming along but Im not sure how to connect the Access forms to the SQL Server views.
So far I have all the tables linked to SQL Server and Im working on migrating the Access queries into views, but Ive got this error, A2SS0069: External variable cannot be converted
which references a form in my Access file:
SELECT TOP 9223372036854775807 WITH TIES
[AcuteHospitals].[NHSN_ID],
[AcuteHospitals].[HospitalName],
[Location_LOV].[Description] AS Location,
Sum([RateTable_CLABData].[clabcount]) AS [Number of CLABSI],
Sum([RateTable_CLABData].[numcldays]) AS [Central Line Days],
[RateTable_CLABData].[CLAB_Mean] AS [National Average]
FROM
(([AcuteHospitals]
LEFT JOIN [RateTable_CLABData]
ON [AcuteHospitals].[NHSN_ID] = [RateTable_CLABData].[orgID])
LEFT JOIN [Location_LOV]
ON [RateTable_CLABData].[loccdc] = [Location_LOV].[CDCLoc])
LEFT JOIN [SummaryYQ_LOV]
ON [RateTable_CLABData].[summaryYQ] = [SummaryYQ_LOV].[StartDate]
WHERE ((([SummaryYQ_LOV].[SummaryYQ]) = forms!YQ_Location.text5 ))
GROUP BY
[AcuteHospitals].[NHSN_ID],
[AcuteHospitals].[HospitalName],
[Location_LOV].[Description],
[RateTable_CLABData].[CLAB_Mean],
[RateTable_CLABData].[loccdc]
HAVING ((([RateTable_CLABData].[loccdc]) NOT LIKE '%ped%'))
ORDER BY [AcuteHospitals].[HospitalName], [RateTable_CLABData].[loccdc]
Its the line WHERE ((([SummaryYQ_LOV].[SummaryYQ]) = forms!YQ_Location.text5 ))
So I need to know if it's possible and how to get this new view to connect with the Access form.
The problem is here
WHERE ((([SummaryYQ_LOV].[SummaryYQ]) = forms!YQ_Location.text5 ))
You cannot convert such Access query into a SQL View, but you can use Stored Procedure instead and pass value from the field forms!YQ_Location.text5 as parameter.
Also, you don't need this TOP 9223372036854775807 WITH TIES it is redundant.
You can't reference the Access form in a SQL View directly. You will need to rethink the logic in this. You could either create a number of Views with the appropriate values hard-coded (inadvisable) or convert the View to a Stored Procedure and pass the value in as a parameter.
For example (assuming the parameter is a string):
create proc s_MyStoredProc
#Location varchar(50)
AS
BEGIN
SELECT
[AcuteHospitals].[NHSN_ID],
[AcuteHospitals].[HospitalName],
[Location_LOV].[Description] AS Location,
Sum([RateTable_CLABData].[clabcount]) AS [Number of CLABSI],
Sum([RateTable_CLABData].[numcldays]) AS [Central Line Days],
[RateTable_CLABData].[CLAB_Mean] AS [National Average]
FROM
(([AcuteHospitals]
LEFT JOIN [RateTable_CLABData]
ON [AcuteHospitals].[NHSN_ID] = [RateTable_CLABData].[orgID])
LEFT JOIN [Location_LOV]
ON [RateTable_CLABData].[loccdc] = [Location_LOV].[CDCLoc])
LEFT JOIN [SummaryYQ_LOV]
ON [RateTable_CLABData].[summaryYQ] = [SummaryYQ_LOV].[StartDate]
WHERE ((([SummaryYQ_LOV].[SummaryYQ]) = #Location ))
GROUP BY
[AcuteHospitals].[NHSN_ID],
[AcuteHospitals].[HospitalName],
[Location_LOV].[Description],
[RateTable_CLABData].[CLAB_Mean],
[RateTable_CLABData].[loccdc]
HAVING ((([RateTable_CLABData].[loccdc]) NOT LIKE '%ped%'))
ORDER BY [AcuteHospitals].[HospitalName], [RateTable_CLABData].[loccdc]
END
Just create the SQL server view, and then from the Access font end link to that view. It is easy, not much work.
As for any parameters? Just remove them from the query and views. You then just open up the report using a where clause from the Access client.
In fact using a Access form or report that is bound to a linked table (or in this case view) is easy, and Access will ONLY pull down the reocrds you specifiy in the "where" clause of the open form or open report command.
SQL Server has an excellent (and free) MS-Access to MS-SQL migration tool. It does a very good job of converting MS-Access queries. I haven't tried converting queries with form parameters, but it is certainly worth a look and you may learn some things as well, especially if you plan to convert other queries. http://www.microsoft.com/sqlserver/en/us/product-info/migration-tool.aspx#oracle.

SQL Server Linked Server Example Query

While in Management Studio, I am trying to run a query/do a join between two linked servers.
Is this a correct syntax using linked db servers:
select foo.id
from databaseserver1.db1.table1 foo,
databaseserver2.db1.table1 bar
where foo.name=bar.name
Basically, do you just preface the db server name to the db.table ?
The format should probably be:
<server>.<database>.<schema>.<table>
For example:
DatabaseServer1.db1.dbo.table1
Update: I know this is an old question and the answer I have is correct; however, I think any one else stumbling upon this should know a few things.
Namely, when querying against a linked server in a join situation the ENTIRE table from the linked server will likely be downloaded to the server the query is executing from in order to do the join operation. In the OP's case, both table1 from DB1 and table1 from DB2 will be transferred in their entirety to the server executing the query, presumably named DB3.
If you have large tables, this may result in an operation that takes a long time to execute. After all it is now constrained by network traffic speeds which is orders of magnitude slower than memory or even disk transfer speeds.
If possible, perform a single query against the remote server, without joining to a local table, to pull the data you need into a temp table. Then query off of that.
If that's not possible then you need to look at the various things that would cause SQL server to have to load the entire table locally. For example using GETDATE() or even certain joins. Others performance killers include not giving appropriate rights.
See http://thomaslarock.com/2013/05/top-3-performance-killers-for-linked-server-queries/ for some more info.
SELECT * FROM OPENQUERY([SERVER_NAME], 'SELECT * FROM DATABASE_NAME..TABLENAME')
This may help you.
For those having trouble with these other answers , try OPENQUERY
Example:
SELECT * FROM OPENQUERY([LinkedServer], 'select * from [DBName].[schema].[tablename]')
If you still find issue with <server>.<database>.<schema>.<table>
Enclose server name in []
You need to specify the schema/owner (dbo by default) as part of the reference. Also, it would be preferable to use the newer (ANSI-92) join style.
select foo.id
from databaseserver1.db1.dbo.table1 foo
inner join databaseserver2.db1.dbo.table1 bar
on foo.name = bar.name
select * from [Server].[database].[schema].[tablename]
This is the correct way to call.
Be sure to verify that the servers are linked before executing the query!
To check for linked servers call:
EXEC sys.sp_linkedservers
right click on a table and click script table as select
select name from drsql01.test.dbo.employee
drslq01 is servernmae --linked serer
test is database name
dbo is schema -default schema
employee is table name
I hope it helps to understand, how to execute query for linked server
Usually direct queries should not be used in case of linked server because it heavily use temp database of SQL server. At first step data is retrieved into temp DB then filtering occur. There are many threads about this. It is better to use open OPENQUERY because it passes SQL to the source linked server and then it return filtered results e.g.
SELECT *
FROM OPENQUERY(Linked_Server_Name , 'select * from TableName where ID = 500')
For what it's worth, I found the following syntax to work the best:
SELECT * FROM [LINKED_SERVER]...[TABLE]
I couldn't get the recommendations of others to work, using the database name. Additionally, this data source has no schema.
In sql-server(local) there are two ways to query data from a linked server(remote).
Distributed query (four part notation):
Might not work with all remote servers. If your remote server is MySQL then distributed query will not work.
Filters and joins might not work efficiently. If you have a simple query with WHERE clause, sql-server(local) might first fetch entire table from the remote server and then apply the WHERE clause locally. In case of large tables this is very inefficient since a lot of data will be moved from remote to local. However this is not always the case. If the local server has access to remote server's table statistics then it might be as efficient as using openquery More details
On the positive side T-SQL syntax will work.
SELECT * FROM [SERVER_NAME].[DATABASE_NAME].[SCHEMA_NAME].[TABLE_NAME]
OPENQUERY
This is basically a pass-through. The query is fully processed on the remote server thus will make use of index or any optimization on the remote server. Effectively reducing the amount of data transferred from the remote to local sql-server.
Minor drawback of this approach is that T-SQL syntax will not work if the remote server is anything other than sql-server.
SELECT * FROM OPENQUERY([SERVER_NAME], 'SELECT * FROM DATABASE_NAME.SCHEMA_NAME.TABLENAME')
Overall OPENQUERY seems like a much better option to use in majority of the cases.
I have done to find out the data type in the table at link_server using openquery and the results were successful.
SELECT * FROM OPENQUERY (LINKSERVERNAME, '
SELECT DATA_TYPE, COLUMN_NAME
FROM [DATABASENAME].INFORMATION_SCHEMA.COLUMNS
WHERE
TABLE_NAME =''TABLENAME''
')
Its work for me
Following Query is work best.
Try this Query:
SELECT * FROM OPENQUERY([LINKED_SERVER_NAME], 'SELECT * FROM [DATABASE_NAME].[SCHEMA].[TABLE_NAME]')
It Very helps to link MySQL to MS SQL
PostgreSQL:
You must provide a database name in the Data Source DSN.
Run Management Studio as Administrator
You must omit the DBName from the query:
SELECT * FROM OPENQUERY([LinkedServer], 'select * from schema."tablename"')
For MariaDB (and so probably MySQL), attempting to specify the schema using the three-dot syntax did not work, resulting in the error "invalid use of schema or catalog". The following solution worked:
In SSMS, go to Server Objects > Linked Servers > Providers > MSDASQL
Ensure that "Dynamic parameter", "Level zero only", and "Allow inprocess" are all checked
You can then query any schema and table using the following syntax:
SELECT TOP 10 *
FROM LinkedServerName...[SchemaName.TableName]
Source: SELECT * FROM MySQL Linked Server using SQL Server without OpenQuery
Have you tried adding " around the first name?
like:
select foo.id
from "databaseserver1".db1.table1 foo,
"databaseserver2".db1.table1 bar
where foo.name=bar.name

Resources