Identify row index of specific row within dataset by reference to the principal key - mysql

I have a table "documents", with an id column, which is the principal key. The table has numerous other fields and users can view the table sorted by reference to many of these fields. The table data is displayed within a virtual tree control which requests only the data it requires for the current client area of the tree.
Say my document table had the following structure and data (it doesn't, but the simple eg below is hopefully suffucient to illustrate)
id description date_of_doc
----------------------------------
1 Doc 1 10/05/1987
2 Doc 2 11/06/1988
3 Doc 3 12/07/1989
4 Doc 4 13/08/1990
5 Doc 5 14/09/1991
6 Doc 6 15/10/1992
My virtual control loads the date in id order is as per the default table order.
However, the control allows you to click on headers which are called "description" and "date_of_doc". Clicking on these headers changes the order in which the data is displayed in the control. Click the same header twice and it will sort descending. I issue a new query to get the data with an "ORDER BY" command depending on what header has been clicked.
So if I am sorting by date_of_doc and it is descending then the new position of id 2 is in fact 5. Having sorted my user then clicks on the "Find by ID" link to find the document with the id "2". I now need to take him to the correct node within my tree control to find this document. From the simple dataset above we can work out that the new index of this position within the tree is 5. But how do I do that with a query taking into account the Order by clause.
Currently I am selecting the id field for every row in the table using the same Order by and then iterating through the query result until I can match the document id with the id requested by the user. There is nothing wrong with this query in the sense that it gets me the correct position, it just strikes me as grossly inefficient especially as I need to work with large tables.
What I am looking for is a query which is something like
SELECT row_num FROM documents WHERE id=12345 ORDER BY date_of_doc

However, the control allows you to click on headers which are called
"description" and "date_of_doc". Clicking on these headers changes the
order in which the data is displayed in the control. Click the same
header twice and it will sort descending. I issue a new query to get
the data with an "ORDER BY" command depending on what header has been
clicked.
This is not very efficient as it needlessly hits the DB everytime someone tries to sort columns. You can retrieve data once per usersession and either cache the data on the Web Servers Memory and sort it in memory. Or use some client side sorting techniques using many javascript libraries ... Iam not an expert on these techniques but you should be able to find help on this topic as it is a very common scenario. Also you haven't mentioned what technology stack you are using to build your web app. C# asp.net, java , php, etc ...
So assuming that we are sorting in memory the only other call to the db would be to fetch the document for the particular requested document.
That said for your immediate need to avoid iterating rows to find
To do that you can write a Stored procedure that takes the DocID and returns the recordset like so ( just pseudocode may need to tweak it for your actual scenario ) :
Create GetDocDetailsByID
(
#id int
)
Begin
select id, description, date, ....
from yourtablename
where id = #id
End
You should have that doc id in your application at run time when the user performs a button click or hits a hyperlink. Call the above SP with that ID. this part is platform specific. So let me know what is your front end platform and we can see if that needs tweaking.

Related

Best Approach for Bookmark Drill through in Power BI

I have a single session date(Day) chosen on the Dashboard home landing page ( page 1) via a dropdown date slicer. The chosen date is a selected date measure defined as:
SelectedDate = cALCULATE(max('Date'[DayTextLong]),FILTER('Date',SELECTEDVALUE('DateSelector'[DateId],MAX('DateSelector'[DateId])) = 'Date'[DateId]))
DateSelector table is a standalone disconnected date table that is a cutdown list of dates for dropdown to select a day for slicer. There is a connected DATE table in this data model.
On a scorecard on the Dashboard home landing page ( Page 1), for a daily amounts on sessions I have a bookmark( as cant drill through on scorecards), to a details table and on that page 2, I want to show the details of which customers. This is from a table that contains a request date and I need to filter the table by the selecteddate measure . How can I show a summarised table visual on Page 2 that filters from the Selected Date measure chose on Page 1?
I was trying to create a measure (Request Date Boo) that would set a measure to 1 or 0 for the relevant records to show from Session Requests table , which is just Session Name, Customer Name and request date , and then put a visual filter on for page 2 to say where Request Date Boo=1. This fails with an error around single value not being found as it telling me I need to aggregrate the request date.
I want to do this properly and wondered what is the normal way of showing a visual on page 2 of a Report , where you want to use a date and apply a filter to another table in the data model using that date.
Hope the question makes sense.
For what I understood, you have a filter on page 1, that must be kept when you navigate to page 2.
I've got three options:
Put the same date filter slicer on page 2 and allow it to sync with the others. In this way, when you navigate between pages that share synced slicers the filters will be kept. (this was also suggested by a comment)
Use the drillthrough functionality (docs here). This is a bit more complicated and does not create a "standard" page but it allows you to navigate to a detail page, based on a set of configured fields, when you navigate to this page you can also keep all the filters that were set before reaching this page. (This is a bit complicated to explain, the best thing you can do is to try it and see if it suits your needs)
Use What If parameters (docs here). I've never used for something like that, but if you can use them to choose a date you may use them to solve your problem.
All considered, probably the first solution is the easiest and most common solution for this kind of problem

Sequential Number in Access Form Based on Field Selection

Hoping someone can assist here, I'm fairly new to SQL but yet the most experienced person in the office so this job has fallen to me.
I'm trying to build a form that will insert customer orders into production scheduling. The form allows users to select a machine from the machine list table, however what I need it to do after that is find the last job number for that specific machine and show the next sequential number in a text box; and that's where I'm stuck. The goal is that when the production user is adding an order to the database, by selecting their machine the next available job number is automatically populated. The information entered will be saved to a master scheduling table.
I've got a query built that pulls the entire list of machine and job combinations, as my goal was to build a macro that could search from that list, but so far I haven't gained any traction. Any help/advice would be appreciated!
Welcome to SO.
My suggestion would be to create a table to hold the sequence numbers. For the sake of this example, let's call it ProdSeq, which means Production Sequences. As part of this table definition, I would use Data Macros (Access 2010 and up) in order to assign the sequences as records are added. I would use a Unique index in order to ensure no duplicates are created.
Table: ProdSeq (Field Definitions)
MachineID (Number - Long) - References Machine ID in Machines Table
ProdSeq (Number - Long) - Incremented for each machine
OrderID (Number - Long) - References Order ID in Orders Table
Indexes
Under the Design ribbon tab when designing the ProdSeq table, click the Indexes button.
Create an Index called UniqueKey
Row 1: Index Name = UniqueKey, Field Name = MachineID
Row 2: Index Name = Leave Blank, Field Name = ProdSequence
Click on Row 1, Column 1 and set the following Index Properties:
Primary = Yes
Unique = Yes
Ignore Nulls = No
Data Macros
Under the Design ribbon tab when designing the ProdSeq table, click the Create Data Macros button, and then the Before Change button. Enter the following data macro: (Pastebin link)
Create the Before Change data macro and set it as follows:
If [IsInsert] Then
SetLocalVar
Name LatestProdSequence
Expression = 0
Look Up A Record In ProdSeq
Where Condition =[ProdSeqLookup].[MachineID]=[ProdSeq].[MachineID] And
[ProdSeqLookup].[LatestSeq] = True
Alias ProdSeqLookup
SetLocalVar
Name LatestProdSequence
Expression =[ProdSeqLookup].[ProdSequence]
SetField
Name ProdSeq.ProdSequence
Value = [LatestProdSequence]+1
SetField
Name ProdSeq.LatestSeq
Value = True
End If
Pay special attention to the fact that only one SetLocalVar is within the LookUpRecord clause. Use the collapse / expand (-/+) button on LookUpRecord to make sure.
Create the After Insert data macro and set it as follows: (Pastebin Link)
For Each Record In ProdSeq
Where Condition = [ProdSeqFlagFix].[MachineID]=[ProdSeq].[MachineID] And
[ProdSeqFlagFix].[LatestSeq]=True And
[ProdSeqFlagFix].[ProdSequence]<>[ProdSeq].[ProdSequence]
EditRecord
SetField
Name ProdSeqFlagFix.LatestSeq
Value = False
End EditRecord
Test it Out
You can create this in a blank database in order to see what I am talking about. You should be able to adapt it to your specific situation.
Form
On your form, when the user selects a machine and order, you can use VBA in order to check for an existing record in ProdSeq, and fetch the ID. If no record exists, then you can create one, and then return the ProdSeq ID to the form.
Note: Depending on your design, you may also need to create a Data Macro on the Schedules table. Suppose someone creates a schedule with a specific machine and order and reserves a production slot. Now assume they change the Order ID .. we have a production slot reserved in error. So if this applies, you'll also need an AfterUpdate data macro on the Scheduling table that checks to see if [old].OrderID <> [Schedule].OrderID - and if they do differ, to remove the Production slot from the schedule table and the Prod Sequence table.
As I understand, you need to add suggested value for job number when you add new record to the table. If so, you can use, for instance DMax function. Here is example of VBA code for this, it can be called when you add new record:
Me.MyTextBox = DMax("JobField", "JobsTable") + 1
I supposed that JobField, which contains job numbers has Number data type.
Also you can use this function inside any query as a calculated field.

MySQL query performance for paginating

Ok, so what is the best practice when it comes down to paginating in mysql. Let me make it more clear, let's say that a given time I have 2000 records and there are more being inserted. And I am displaying 25 at a time, I know I have to use limit to paginate through the records. But what am I supposed to do for the total count of my records? Do I count the records every time users click to request the next 25 records. Please, don't tell me the answer straight up but rather point me in the right direction. Thanks!
The simplest solution would be to just continue working with the result set normally as new records are inserted. Presumably, each page you display will use a query looking something like the following:
SELECT *
FROM yourTable
ORDER BY someCol
LIMIT 25
OFFSET 100
As the user pages back and forth, if new data were to come in it is possible that a page could change from what it was previously. From a logical point of view, this isn't so bad. For example, if you had an alphabetical list of products and a new product appeared, then the user would receive this information in a fairly nice way.
As for counting, your code can allow moving to the next page so long as data is there to support a new page being added. Having new records added might mean more pages required to cover the entire table, but it should not affect your logic used to determine when to stop allowing pages.
If your table has a date or timestamp column representing when a record was added, then you might actually be able to restrict the entire result set to a snapshot in time. In this case, you could prevent new data from entering over a given session.
3 sugggestions
1. Only refreshing the data grid, while clicking the next button via ajax (or) storing the count in session for the search parameters opted .
2. Using memcache which is advanced, can be shared across all the users. Generate a unique key based on the filter parameters and keep the count. So you won't hit the data base. When a new record, gets added then you need to clear the existing memcache key. This requires a memache to be running.
3. Create a indexing and if you hit the db for getting the count alone. There won't be much any impact on performance.

MySql paginated results, find "page" for specific result

I have an application using a MySql database which is displaying a paginated list of records, to which to which the user is able to add new ones. I know how to get paginated results using LIMIT etc, but the question is how to go a specific page when adding a new record. If the page size is 20, and the user is viewing the first page, and they add a record which is 23rd (out of say 100), how do we determine which page to show the user.
So, essentially, given a page size and a specific record, how do I determine which "page" to show out of the pages. The total pages do NOT include all of the records for the table they belong to, but the criteria for getting them is static.
Edit:
I should have been more specific. The records contain a unique ID field and a string name field. The resultant records are sorted by the name alphabetically. Also, this is a java application.
The only thing I can think of is to select all the desired records sorted by name and then some how find the position in those results of the specific record. From that position the page number could be easily calculated since we know the page size, but I'm not sure if they is MySql syntax for getting the position of a record in the results.
The "dumb" solution would be to just grab them all and then in the application code (java), determine the specific records position in all the results. But is seems like their must be a more efficient way.
SELECT COUNT(*) as CNT FROM tbl WHERE name < (SELECT name FROM tbl WHERE id = 42)
After that you just divide CNT value to the amount rows per page and round (Math.floor()) it
Or you can even do that in sql:
SELECT FLOOR(COUNT(*) / 20) AS page_number ...

Access Form Field Logic

I'm trying to make access conditionally only show rows that meet a certain condition, allow me to give you some background info before I proceed :
I've created an Access form and linked it to a test DB on my machine. The particular table I am interested in contains the following (important) rows :
ID , Office, Name, SecurityNumber
The thing is, ID is not unique. There are two Office locations, and each Office has it's own set of unique ID numbers. This means that ID 10 here and there may or may not be the same person. (this data comes out of a legacy security system we're not looking to change yet, so I cannot change it)
But ID -is- unique to each Office.
SO! I created an Access form with TABS! Two tabs, one for each office. What I am trying to achieve now is :
Have the ID/Name/SecurityNumber fields for each tab populate with only rows that match it's particular 'Office' value.
Thank you for reading and thank you for helping! :D
If you want the data for the office locations presented in separate tab page controls, you could use subforms on the pages which differ only in the WHERE clause of the queries used as their record sources. So for the Office1 subform, the query could be:
SELECT ID, Office, [Name], SecurityNumber
FROM YourTable
WHERE Office = 'Office1'
ORDER BY [Name];
Then for Office2, the query would be the same except for the WHERE clause:
WHERE Office = 'Office2'
As I understand your question, that approach would do what you're asking for.
However, that's not really the easy "Access way" to do it. Instead consider a combo box control to allow your users to choose which office they want to view. In the code for the combo's after update event, either modify the SELECT statement used as the form's record source or create a filter expression an apply it.
Also, since you're pulling the form's data from SQL Server, consider whether you want your form to load every record for the selected office location. It may not be much concern if you have only a few to moderate number of rows for each location, but if you'll be dealing with multiple thousands of rows it could be. In general, you should try to avoid pulling copious amounts of data across the wire; pull sparingly instead ... only what you need for the immediate task at hand.