Can an SSMS add-in have access to a resultset? - ssms

Can an SSMS add-in have access to resultsets? I would like an add-in tools menu item that can generate into the clipboard a DECLARE #Result1 TABLE ( ... ) (including the name, type, length, precision, etc) for each of the results in the most recently returned resultset. I see some discussions about accessing the result Grid UI directly, but by then some of the metadata would have to reconstructed from the grid values rather than from the resultset directly.
It seems to me that such an add-in would be useful when intermediate results need to be captured into an intermediate value for reuse, not having to go look up all those column types from all the joins.

Related

'Update requires a valid UpdateCommand when passed DataRow collection with modified rows.'

In my application I have three tables all from the same Access database. I have used the Wizard in Visual Studio Express 2019. This is an extension of my unresolved question here.
Database.TwixBindingSource.EndEdit()
Database.NPCsBindingSource.EndEdit()
Database.EffectsBindingSource.EndEdit()
Database.TableAdapterManager.UpdateAll(Database.DatabaseDataSet)
I have these three tables ("Twix","NPCs",and "Effects"). The above code automatically runs every 15 seconds, like an autosave feature. My issue is when I try to edit "NPCs" or "Effects" I recieve the following error:
'Update requires a valid UpdateCommand when passed DataRow collection
with modified rows.'
Most of the online answers in regard to this error are solved by ensuring each table has a Primary Key column that is recognised by Visual Studio in order to automatically generate the necessary commands to edit, updte, delete etc.
However, I am stumped because I have PKs on each table.
The only thing I can think is that it has something to do with the 'TableAdapterManager,'
ALthough I have no clue at this point.
EDIT: I have replaced the UPDATE ALL with individual UPDATES, but the same problem persists...
Database.TwixBindingSource.EndEdit()
Database.TwixTableAdapter.Update(Database.DatabaseDataSet)
Database.NPCsBindingSource.EndEdit()
Database.NPCsTableAdapter.Update(Database.DatabaseDataSet)
Database.EffectsBindingSource.EndEdit()
Database.EffectsTableAdapter.Update(Database.DatabaseDataSet)
Right click on your tableadapter (on the header, not the Fill command), and choose Configure
Click Advanced Options and verify that "Generate I/U/D" is ticked
When this isn't ticked, the resulting TA doesn't have any DML statements built:
If your SELECT statement doesn't select the column that is set as the primary key in the database, then this Generate IUD tickbox may be greyed out, or it will be ticked but the DML statements won't generate. Pay attention to the final page of the wizard. Here is what happened when I made a table "Other" that had no primary key:
INSERT generates, because it's easy to generate an insert on a keyless table, but update and delete cannot be generated
If you don't select the PK column you get a warning:
It's important that your DB tables have a PK; it's not the same thing to declare some datacolumns of a datatable in a dataset to be a primary key. A Dataset is not a database; it may have more or fewer tables/columns and the presentation and datatypes of row data do not have to match the DB. I can see that your dataset screenshot shows some tables have PKs declared in the DataSet side, but this is not a statement that they are definitely PKs on the DB side
Feel free to delete the DataTable; it will delete the TableAdapter too. You can then recreate that one TA by right click, new, tableadapter.. SELECT * FROM table
If you hadn't already realized, remember that you can (and should) declare more queries per tableadapter than just keeping with the basic Fill, which appears to be a SELECT * FROM without a WHERE clause in your case. Personally I always make my first query SELECT * FROM table WHERE id = #id because it's really rare that you want to download a whole table.. You can leave the default as a WHEREless query, but consider adding others, such as SELECT * FROM Twix WHERE Location = #location and naming the query FillByLocation. In code you can then fill just the locations you want, rather than downloading 10000 Twixes into the app just to show some of them (with a rowfilter, i guess)
This question and answers helped me figure out my problem.
NOTE that if your problem is your table (for example you forgot to set a primary key and you go back and fix it in SSMS while debugging) you will need to find the menus in Caius answer, ensure boxes are ticked, and hit Finish if nothing else.
This will refresh something about the statements(unclear what), and allow this to work. Otherwise you will continue to receive these errors as if you'd fixed nothing, and probably continue to search to no avail.

Read/Write SQL Server views in MS Access using SCHEMABINDING

I am having to redevelop an MS Access 2003/2010 ADP project, that uses SQL Server views as the RecordSource for all its forms, into an MS Access 2016 ACCDB.
I have tried using pass through queries to get the data and this works fine for readonly columns, however when I want to change the value in one of the bound columns, it says that the RecordSet is not updateable, which is what you might expect if using a view.
But I have now read that if you define the view with SCHEMABINDING like this:
ALTER VIEW [dbo].[vwQuote_MinibusesDetails]
WITH SCHEMABINDING
AS
SELECT ...
and add a UNIQUE CLUSTERED INDEX like this:
CREATE UNIQUE CLUSTERED INDEX CIX_vwQuote_MinibusesDetails
ON vwQuote_MinibusesDetails (txtQuoteNo, txtVersion, txtVehicleNo);
and then add the view to your project as a DSN-less TableDef like this
stConnect = "ODBC;Driver=SQL Server;Server=" & SERVER_NAME & ";Database=" & APP_DATABASE & ";Trusted_Connection=Yes"
Set td = CurrentDb.CreateTableDef(stLocalTableName, dbAttachSavePWD, stRemoteTableName, stConnect)
CurrentDb.TableDefs.Append td
it becomes editable as if it were a table.
However, when I open the TableDef in Access it shows all the rows and columns as if it were editable, but if I try to edit a column, it says that there is a Write Conflict with another user's changes, when I am 100% sure that there isn't because I am the only person using it.
Any ideas? (I am using Access 2010 at the moment)
But why do all that truckloads of work? There is zero reason to do all that extra work.
Simply bind and set the forms data source to a view. It is assumed that you will simply link all of the existing views on the client side. Access will thus see all the views as simply tables, and views (as opposed to Pass through queries) are read/write.
So, there is no need to:
Have ANY connection strings in your code. If you ARE using connection strings in code, then you approach is all wrong. Just link to the views, and set the forms data source as that view.
At this point, the forms can edit data.
As for a pass-through quires to drive combo boxes? Do NOT do this. While a PT query is likely the fastest way to pull data, the access client cannot filter PT queries. So you ONLY EVER want to use a PT query for cases in which the client side does NOT have to filter the results. If you bind a combo box to a PT query, then Access needs and wants to ONLY pull the one value from that table for display. And since the access client can’t filter a PT query, then it will scan the WHOLE data source for that combo box to get the one value that is currently displayed. If you use a linked table (or even a view) to that source that drives the combo box, then the access client can filter that dataset to the ONE row. So, do NOT use a PT query for ANY case in which client side filtering is required. A linked view (or linked table) is fine in these cases.
So, just bind the forms directly to the linked table, or the linked view.
If the table has 1 million rows of data, and you say do this:
Docmd.OpenForm "frmInvoice",,,"InvoiceNum = 1234"
Access will open the form to the ONE row of data, and ONLY pull one row down the network pipe. This is despite that the form in question is bound to a table of 1 million rows. The form will load instant, and you not had to write any sql, any connection stuff, and not really do anything different then how you developed typical access applications.
Bound forms are how and why Access saves huge development dollars. If you jump to .net, then you have all kinds of tools and wizards that can help you around this issue. So in .net, you could adopt the dataset designer, or use the newer entity framework.
In Access, we don’t have this huge tool box of data designers and tools, so if you attempt to hand code, and code up the data sources for a form, then you get the worst possible outcome (you write truckloads of code, and don’t have all those cool tools for un-bound forms).
Simply link your forms to linked tables (or views) and you now have a working data bound form without any code. If you need to load the form, then use the 20+ year standard approach of the “where” clause of the open form command to open the form to the one record. The access client will ONLY pull what you put in the “where” clause.
So, to wire up a form for editing of data, ZERO code is required. The only developer efforts will then to ensure that the form does not pull un-necessary data to the client.

Choose AS400 query records directly from Excel

I've been searching the internet for hours trying to figure out if the following is even possible:
To choose the AS400 query records directly from Excel.
I haven't found any solution or description of how this could be achieved, which makes me guess that it's simply not possible. However, I haven't seen anyone confirm that it is impossible.
So my question is: Is this possible? And if it is, could you point me in the right direction in order for me to start learning how to do it?
I know its possible to run a query from Excel, and then adding parameters via SQL statements, but in my case, this presents several problems that could be avoided by choosing the records before the query is executed.
Example:
I have a query with a column (lets call it ColVal) that can hold the values 1 and/or 2. In the AS400 program under the menu "Work with queries" and then "Choose records" I can specify which records the query should contain when it has run based on the value in ColVal. This means i can get three different situations (A, B and C) when i run the query:
A) The query only contains records where the value in ColVal is 1
B) The query only contains records where the value in ColVal is 2
C) The query contains records where the value in ColVal is either 1 or 2
The goal is to be able to choose which situation I want from Excel in order to circumvent opening and using the AS400 program.
However, using situation C and then editing the query in Excel with an SQL statement to mimic situation A or B is not an option, as this means the query still contains undesired records.
This whole thing boils down to the following: Is it even possible to run the query from Excel essentially changing the data it contains and not just outputting it to excel? If this is possible, is it then possible to pass a parameter to the AS400 system and use it to create situation A, B or C?
I hope this example makes sense.
Edit - New example
Say i have different customers A and B. I can open the AS400 program and run a query in which i have specified that I only want data on customer A. I can then open Excel and use filters (as Hambone described) on the query to determine which records I want to output. However, if I want to work with data from customer B, I have to open the AS400 again and run the query with different parameters. I would like to be able to "change" my dataset from customer A to B from Excel, without having to include both in my recordset and then filter out one of them.
I imagined this is doable if you could pass a parameter to the AS400. The AS400 then runs the query using this parameter as the criteria for which records should be stored in the query. This means that if the parameter is Customer B, then there is no way to acces data from customer A, without running the query through AS400 again.
Any ideas are greatly appreciated :)
Follow up to my comment, here is a quick primer on how to run an ODBC query directly in MS Excel using Microsoft Query. This is very different than Power Query, which you referenced, in that MS Query is standard with Excel -- it's not a plug-in. This is relevant because it means everyone has it. If you are deploying a solution to others, that's an important consideration.
To start an MS Query in Excel, go to the data tab, select "From Other Sources" -> "Microsoft Query."
A list of your ODBC connections will come up. Pick the one that you want and select "OK."
It may or may not ask you for a login (depending on which ODBC connection you use and how its configured).
The next part is important. MS Query is going to try to have you use its builder to create the query. If you have the SQL, skip this part. It's horrible. Click "Cancel" on the query wizard, and then click the "SQL" button to enter your own SQL. If you can, make sure the result set is small (like use where 1 = 2 in the query).
When MS Query returns results, click the button next to the SQL Button to have it return the results to the spreadsheet. It looks like a little door.
From here, any time you want to refresh the query, you can simply right-click the data table in Excel and select "refresh." Alternatively you can go to the data tab on the ribbon and select "Refresh."
By the way if you have linked pivot tables and charts, the "Refresh All" option will refresh those as well, in the correct order.
To edit your query at any time, right-click on the table in Excel, go to Table-External Data Properties:
Then Click on the Connection Properties icon (highlighted below)
Click on the second tab (Definition) and edit the SQL Directly.
Parameters can be declared simply by inserting a bare "?" in place of your literal.
In other words, if your query looks like this:
select *
from users
where user_id = 'hambone'
Just change it to:
select *
from users
where user_id = ?
Excel will prompt you for a user id before it runs the query. From here, you also have the option of putting the parameter value in a cell within the spreadsheet and having the query read it from there. You'll see these when you right-click the table and go to the "Parameters" menu option.
Let me know if this helps or is unclear.
-- EDIT 7/23/2018 --
To follow up on your latest edit, it is possible to handle the scenario you describe, where you want to be able to filter on a value, or if none is given, then not have a filter. You see this a lot when you present multiple filter options to the user and you want a blank to mean "no filter," which is obviously counter to the way SQL works.
However, you can hack SQL to still make it work:
select * from activities
where
(activity = ? or ? is null) and
(energy = ? or ? is null)
In this example you have to declare four parameters instead of two, two for each.
You might also have to play with datatypes, depending on the RDBMS (for example for numerics you might have to say ? = 0 instead of ? is null or even ? = '' for text).
Here is a working example where a single filter was applied on the query above and you can clearly see the second one did not have an impact.
Yes it's possible. You need to use an ODBC driver to connect to the AS400 and retrieve the data. The driver and documentation are Here

Oracle SQL XMLElement only outputting (XMLTYPE)

I have a small query to output XML.
CODE:
SELECT XMLElement("NAME", e.name)
FROM person e
Output:
XMLELEMENT("NAME,E.NAME)
(XMLTYPE)
I'm new to the XML side of things in Oracle, why isn't it outputting XML?
There is a setting in the preferences to let it show the actual XML in the Query Results window.
Go to SQL Developer's Tools menu, pick Preferences, expand the Database section, and go to the Advanced section:
Tick 'Display XML Value in Grid', click OK, and re-run your query.
When that option is not set you can still view a single row's actual value by right-clicking on the (XMLTYPE) in the grid and choose 'Single record View...`, but unless you're verifying a few large documents that is a bit clunky.
Or, as #WernfriedDomscheit suggested, you can change your query to get the CLOB value from the XMLType instead. (Including XMLAgg(), which returns an XMLtype too).
Also, if you run your query as a script (F5) instead of as a statement (control-enter) the XML is displayed in the Script Output window regardless of that setting (since it only applies to the grid view). You may need to set long to a higher value to see a useful amount though, as the default is to not show very much at all.

Dynamic Parameter in Power Pivot Query

We are using Excel 2013 and Power Pivot to build modules that consist of several Pivot tables that are all pulling data from the same Power Pivot table, which queries our T-SQL data warehouse.
In an effort to simplify and fully automate this module, we wanted to create a text field that would allow a user to enter a value (a client ID# for example), and then have that value be used as a parameter in the Power Pivot query.
Is it possible to pass a Parameter in the Power Pivot query, which is housed in a text field outside of the query?
You can also pass a slicer or combobox selection to a cell. Define a name for that cell. Put that cell (and others if you have multiple text variables to use) in a table. For convenience, I usually name this table "Parameters". You can then 'read in' the parameters to your query and drop them in your query statements.
The code at the top of your query to read these parameters in might look like...
let
Parameter_Table = Excel.CurrentWorkbook(){[Name="Parameter"]}[Content],
XXX_Value = Parameter_Table{1}[Value],
YYY_Value = Parameter_Table{2}[Value],
ZZZ_Value = Parameter_Table{3}[Value],
Followed by your query wherein instead of searching for, say a manually typed in customer called "BigDataCo", you would replace "BigDataCo" with XXX_Value.
Refreshing the link each time a different customer is selected will indeed be a very slow approach, but this has worked for me.
Rather than pass a parameter to the data source SQL query, why not utilize a pivot table filter or slicer to do allow the users to dynamically filter the data? This is much faster than refreshing the data from the source.
If for some reason you need to pass this directly to the source query, you'll have to do some VBA work.