Use a query to sort a report in MS Access - sql-server

I am a beginner in MS Access and am currently stuck with a problem.
I have a database about movies and I'm currently creating a list of all the movies that I want to have sorted by popularity.
To determine the popularity of a movie I have a different table that has a history of what my customers have watched, every movie they have watched is a seperate entry in that table.
I have created a report that has 3 things, the title of the movie, the ID of the movie and a button to watch that movie. But I want to sort the report to show the movies with the most viewers first.
I have created this code in SQL Management Studio which works exactly like I want too:
SELECT [Film].[Titel], [Film].[Film_ID], COUNT([historie].[Film_ID]) as timesWatched
FROM [Film] INNER JOIN [historie] on [Film].[Film_ID] = [historie].[Film_ID]
GROUP BY [Film].[Titel], [Film].[Film_ID]
ORDER BY timesWatched DESC
I'm not that good with Access yet and have no idea how I can use this query to sort the report, I tried putting it in the row source (with everything on one line) in the report properties, which didn't work.
I hope someone has an idea on what to do, is it possible to use this query somewhere or should I use something else than a Report?
Thanks in advance for the answers!

If I'm not wrong..
First create the Query in ACCESS (Create tab -> query) There you will be able to create that query, save it, then go to your report and set its source to this query, the last step will be to set each textbox/label source to the query field, I mean if you have a textField in your report where you want to diplay "movieName", you must select data source from this text box and choose between all fields in your query (in this case, and following a good practice, let's say the field is called movieName too).

Related

How can I traverse through multiple related objects based on ID and return some related field?

I'm a little stuck.
I am trying to generate a report that determines whether anyone has made a manual change to certain fields within our order framework. I have figured out the proper fields and structures to audit, and even how to make the report, but I used a combination of extracts from the Dataloader and Excel xlookups to make it. Now, I'm being asked to find a way to automate the generation of the report, and I suspect that means I need to write a SOQL query to figure it out. I'm having trouble traversing multiple relationships based on these ID fields. Essentially, what I'm trying to do is make multiple "left joins" based on the 18 digit Salesforce IDs and extract some related piece of information from those other objects.
For example, if I'm starting with order_product_history (with a field OrderProductID to identify the order product) and I want to bring in "Product Name", I have to first match OrderProductID with the ID field in my order_product "table", then I have to match the Product2ID field in my order_product "table" with the ID in my product "table", then I have to get the matching Product Name as a column in my report:
Matching/Traversal Process
Desired Result
That's one example for one field. I also have to bring in things like User Name from the users "table", and order number from the orders table, but once I get the general idea, I think I'll be OK. I also want to filter the results to only include my Fee__c and UnitPrice fields, ignore the automated users and set a date filter--not sure if I have to do that using a WHERE clause just in my main query, or if I have to filter the subqueries as well.
I am not a programmer and I have no formal Salesforce training; I am just an analyst who is technically inclined and sort of fell into the role of Salesforce Admin. I am familiar with programming concepts and have been writing things using the flow application and have even dipped my toes into some Apex stuff, but it can be a bit of a struggle. I am not asking you to do my job for me and I am willing to work at the problem and learn; any help is appreciated. Sorry about the links; SO won't let me embed images yet.
There's high chance you don't have to write any code for it. I'll give you some tips, experiment a bit and edit the question or post new one?
This diagram might help: https://developer.salesforce.com/docs/atlas.en-us.api.meta/api/sforce_api_erd_products.htm
Developer way
It's all about writing the right query. You can play with it in Developer Console or Workbench for example. Read up about relationship queries in SF.
https://developer.salesforce.com/docs/atlas.en-us.soql_sosl.meta/soql_sosl/sforce_api_calls_soql_relationships_understanding.htm
https://developer.salesforce.com/docs/atlas.en-us.soql_sosl.meta/soql_sosl/sforce_api_calls_soql_relationships_query_hist.htm
I don't have org with orders enabled but this should be a good start:
SELECT CreatedById, Created.Name,
Parent.Name, Parent.Product2.Name, Parent.Order.Name,
Field, OldValue, NewValue, CreatedDate
FROM OrderItemHistory
If it throws errors about "Parent" see if "OrderItem" will work. Once you have it - WHERE Field IN ('UnitPrice', 'Fee__c') AND CreatedDate = LAST_WEEK might be good next step. (dates can be filtered by date but there are few "constants" that are more human-readable too)
You could even export this with Data Loader, you just have to start the wizard on Order Product history table. But you can ignore the whole query creator and paste a query you've created.
Admin way
Have you ever created a report in Salesforce? There are self-paced trainings (for Lightning and Classic UI) and tons of YouTube videos. Get a feel of making few reports.
What you want might be doable with built-in report type (see if there's new report -> order product history). If nothing exciting - as admin you can make new report type in setup. For example Orders -> Order Products -> Order Product History. Screenshots from here might help.
Just wanted to update this for anyone looking for a solution in the future.
Turns out you can traverse these as a parent-child relationship in the SOQL query. Here's the query I ended up using:
SELECT CreatedBy.Name, FORMAT(CreatedDate), OrderItem.Order.OrderNumber, OrderItem.Product2.Name, OrderItem.Product2.ProductCode, Field, OldValue, NewValue
FROM OrderItemHistory
WHERE (Field = 'Fee__c' OR UnitPrice) AND (CreatedBy.Name != 'Integration User') AND (Created Date >= 2020-11-24T00:00:00.000Z) ORDER BY CreatedDate DESC

VB/SQL - How To Filter DataGridView From Joined Table With Multiple Matches

I'm using SQL Server and Visual Studio 2019.
I'm looking for advise on the best way to filter my documents list (in DataGridView) based on what view they appear in.
I have 3 database tables shown below:
I have simplified my Document table for this post, but there is quite a lot of details for each document displayed in the DataGridView.
I fill a DataTable which I use to apple into a DataView which is then used at my DataGridView DataSource.
Within the SQL that fills the DataTable I have a custom column that uses a JOIN to determine the View that each document appears in, I later then filter the document list based on the custom column.
This only really works if the document only appears in 1 view, as otherwise the JOIN retrieves multiple entries of the document to cover each View matched. (hope that makes sense).
I have simplified the View table for this post also, a View can contain Sub Views if you like i.e.:
View 1
> Sub View 1
> Sub View 2
> Child of Sub View 2
This means a Document can appear more than once in a View as it may appear in various Sub Views.
I'm wonder if I'm best to carry on retrieving the Custom Column or if I should be running a whole new SQL query and even creating a new DataTable / DataView based on the View table.
Some of our workers are remote and some projects can contain thousands of documents, so I want to ensure I used the most robust method, but also one that will cause the least delay on retrieving the information and give the user the best experience.
I hope I've explained everything enough for you guys to get the list of what I'm trying to achieve.
Thank you in advance and I would appreciate any help on this.
>
>
Edit - Following first answer post:
As you say I probably haven't explained enough, so I've put together a visual example of what I'm trying to achieve.
When a project is loaded all documents are listed, the TreeView hasn't been clicked so no filter is applied. All documents are listed:
If a user clicks "View 1 > Sub View 2" on the TreeView it filters based on the data in CustomJOINColumn, see below:
If a user clicks "View 1 > Sub View 1" or "Another View > Documents" on the TreeView it again filters based on the data in CustomJOINColumn, see below:
As you can see Document D001 has appeared in 3 different views/sub views.
The problem is shown in the first image. Document D001 is listed 3 times as it is associated with 3 views/sub views.
I only want Document D001 to appear once in the first list, but when the corresponding Node in the TreeView is clicked it filters correctly as shown.
I hope this makes sense.
There might be some details of your case that indicate a different solution, but from what you have here it sounds like you should drop the special column, drop the full-fill with filtering, and implement a focused fill for your DataGridView. It doesn't even involve much of a change, a slight modification rather than a major rewrite.
Why? Because especially if you have remote workers on a WAN, the performance hit of loading the full list of documents will be crushing if you have many large views. A focused load allows you to spend time loading only the relevant document details. You get the first 500ms or so "for free" with users, but if you take even 30 seconds to load and filter they'll think it's crashed. And your application takes more memory when it's stuffed full of grid rows of document details you'll never use. Plus, as you've already discovered, coming up with a filtering scheme based on membership in an arbitrary number of overlapping groups is really hard, and a focused load is really easy.
So how to do it?
First, go to your DataSet and modify the table adapter with "Add"->"Query". You'll define a new query that uses a parameter (#View) and returns data in the same format as the original, but only for documents in that view. Give it an obvious name, like when it offers a name "Fill" make it "FillByView"
Next, grab a copy of the code in your Form_Load event that fill the grid (something like tadaptDocs.Fill(tblDocList)) and comment it out there, but place a copy in the Change event for the control that the user selects the view in. Change it from "Fill" to "FillByView" and add the #View parameter.
You'll probably want the Form_Load event to set the view to the last View chosen (save in My.Settings) or the first view in the list, that will kick off a Change event and populate the DataGridView with an initial set of documents.
Now, every time the user picks a new view, the grid is loaded with just those documents in that view, regardless of what other views they may be in.
When you save the changes via "Update", VB automatically applies the changes to the underlying data, you don't have to worry that it will truncate your database table to just the documents in that view. It makes an internal distinction between records that were deleted and records that were never loaded. You also don't need to make new versions of the Update, Insert, or Delete methods on the TableAdapter, only Fill Needs a new version that considers View.
EDIT: The following added in response to additions made clarifying the problem
It sounds like a focused load is still called for, but only when the user selects a view. Your initial view should be a "fill all", but modified to strip duplicates. If you have many details in the grid you'll probably want to break that out into 2 parts with a CTE, example follows
;WITH cteCust as (
SELECT D.DocID as DocID, D.docNum , D.docTitle , V.CustJoinName as CustJoin
, ROW_NUMBER() OVER (PARTITION BY D.docNum ORDER BY V.viewTitle) as ViewRank
FROM #tblDoc as D LEFT OUTER JOIN #MapDocView as M on D.DocID = M.DocID
OUTER APPLY fnGetCustJoinName(M.ViewID) as V
) SELECT C.DocID , C.docNum , C.docTitle , C.CustJoin , D.docOther
FROM cteCust as C INNER JOIN #tblDoc as D ON C.DocID = D.DocID
WHERE ViewRank = 1
ORDER BY D.docNum
A few elements of this bear explaining, reply in comments if you need more details
cteCust extracts the core document info and adds the custom join columns, I'm not sure how you're doing it, but a table valued function is one way and I used it for simplicity, substitute whatever you're using. You said there was a lot of document info, this lets you work with just the core details and tie in the other stuff later. We're using a LEFT OUTER JOIN on the Map table because you want docs without a view to still show up in the unfiltered list.
ViewRank is how you get rid of duplicates, by partitioning a ROW_NUMBER function over the Documents, you get only the first view it's in. In the focused fill you want the view filtered on, but you said the initial fill should be just one view so each document appears only once.
Note that the final SELECT ties it back to the Documents table so you can pick up the extra fields.
NOTE: In your example you have a simple membership model - you want Docs that belong to a specific view not a hierarchical one where you want all docs in a view and all sub views (i.e. D006 is in Approved but does not show up when you select the parent Documents in example 3 of your updated question). If those requirements change and your customers want a recursive membership scan, you should post it as a second question, this Q&A is already huge and you'll get fresh eyes on it if it's a new question. Post a reference here too, but make it a new question.

How to link the Tag Items to TestCaseId in Team Foundation Server 2017?

We are trying to create a report to link the Tag Items to their TestCaseIds.
However, the tables in the TFSWarehouse are empty. How would we link these sets of data.
It was very interesting - I did a search on every field on every table in the TFS database and came to know the Tags were actually embedded in XML in the rows. This is a very unique way of placing data, as the XML rows could be readily 'read' by a browser. However, this was very difficult to SELECT and perform JOINS on data.

Trying to delete records or reports in MS Access before a certain date

I have a Microsoft Access Database file.
I wanted to delete records older than 5 years in it.
I made a backup before starting to modify the file.
I was able to run a query and then run the command below and append it or update it to the database file.
DELETE FROM Inspections Report WHERE Date <= #01/01/2013#
I used the example:
Delete by Date In Access
The records still seem to be in there.
My desired Output:
A analogy to what I am trying to do would be the bottom left corner of a Microsoft Word file where you see page 1 of 10 when it should say page 1 of 5 after deleting pages.
DELETE Table1.*, Table1.VisitDate
FROM Table1
WHERE (((Table1.VisitDate)<=#1/1/2013#));
I suggest you make the query object and save it, so it appears in the Navigation Pane and can be tested manually. [In which case you use Query Design View and don't need the syntax above]
Then use the OpenQuery method to fire that query.
To run a sequel command from Access VBA you need to preface it with DoCmd.RunSQL or CurrentDb.Execute, and then put your SQL coding in quotes.
Also, the space is probably causing an issue - if the table you're deleting records from is called "Inspections Report" you'd enclose both those words in square brackets to show its a single entity.
Finally "Date" is a special word in Access, and it doesn't like it when you use it as a field name, as it can cause problems when referencing that field later on. You might try something like "InspectionDate".
So your code would look like this:
DoCmd.RunSQL "DELETE FROM [Inspections Report] WHERE InspectionDate <=#1/01/2013#"
If you have a static date, you'd probably only need to complete this process once, which you could just do in the table by filtering - filter for before that date, use ctrl+a to select all that match that criteria, and hit delete. It will ask if you want to delete them, and you may see that the number of records it's trying to delete is only the number that satisfies your set criteria.
Of course, if you're interested in never having records older than a certain number of years, you could go for something in the original coding like > DATEADD("yyyy", -5, DATE()) and set it to execute every time you launch the database.

Gather inserted text values from multiple rows in a report

I'm currently struggling with Oracle Apex.
I'm trying to create an application which enables customers to place their order. Therefore I create a report which lists the available products. Furthermore the report contains a column (the SQL query for that is simply '0' as "Quantity") which displays a text box. In this text boy the customer should be able to insert the required quantity.
I've create a screenshot to make it easier to follow me:
After the customer has fill out the form, the "Place Order" button will purchase the wished items then.
My question is now, how is it possible to read out in which text boxes did the user filled in a number and also to which product belongs it!
An easier solution would be to recreate the region but choose Form Region and then Tabular Form Region and then the wizard will help take care of the DML for you. But you need to use specific table columns for this to work.
To answer your question more directly - the input items defined in reports that are posted to the server can be accessed in PL/SQL as a set of "Global Arrays". These are defined as PL/SQL tables in the package apex_application with the names g_f01 through g_f50.
To be sure which of these arrays to use for the quantity text box you can look at the html of the page for the name attribute of the input tag. If it is f01 then you would be able to process the results by accessing each position or element in apex_application.g_f01.
To link the input with the table you would need some sort of key. If you use the wizard to build a Tabular Form all this headache is taken care of for you though.

Resources