Pagination and concurrent update - mysql

Lets suppose there is a table products with data
id | product | amount
---------------------
1 | keyboard| 1
2 | monitor | 2
3 | computer| 3
4 | mouse | 4
And userA loads data from this table by two products. So he does
SELECT * FROM products ORDER BY amount LIMIT 2 OFFSET 0 and he gets products with id 1 and 2. However, while userA is reading two first positions userB changed data in table, so it became
id | product | amount
---------------------
1 | keyboard| 3
2 | monitor | 1
3 | computer| 3
4 | mouse | 1
Now UserA need the rest data so he does SELECT * FROM products ORDER BY amount LIMIT 2 OFFSET 2 and he gets products with id 2 and 4 and this is not what he expected.
So we see here that there is a problem with pagination if there are more then one user and some user do updates while other are reading some pages. How are such problems solved? Of course in real example there are thousands of rows + joins.

In the above example, the order by variable is the challenge.
one way you can solve this is by,
In the example, before binding next page query result data to the list, check whether any of the item in the result already fetched in previous query. if so, update those list item with its updated value and skip adding them again. This has to be done in the client side.
And it is always better to audit this kind of data by adding a field like "LastModificationTime" indicating when the row last modified, and display it along with other columns.

Related

Count keys not containing atleast one value in a one to many relationship

My apologies for the nonsense example, the actual data i'm working with cannot be shared.
I have a set of customer baskets containing items forming a one to many relationship.
In BO this results in a table with the basket ID duplicated for each item within that basket.
e.g.
| ID | Item |
|----|--------|
| 1 | Apple |
| 2 | Apple |
| 2 | Orange |
| 3 | Apple |
| 3 | Orange |
| 3 | Pear |
I'm attempting to count the number of baskets that do not contain a pear, however the formulas
=Count([ID]) Where (Not([Item] ="Pear")) and =Count([ID]) Where (Count([Item]="Pear")<1) Both return incorrect results as the initial count can find other rows in the table where basket 3 does fit the conditions.
Is there a formula I can use to check all items relating to basket before counting to return my desired output of "2". I'm trying to avoid breaking up my Data query if at all possible.
Cheers,
The basic concept is to duplicate your query with additional criteria to only return the baskets with pears, left join to it, and count the IDs that are in your original, but not in the duplicated query.
Begin by duplicating your query adding criteria so you only get the baskets with pears.
Next, merge the ID dimensions for both queries.
Create a variable with the Qualification set to "Detail", the Associated dimension as the Merged ID dimension, and the formula as the Item from your duplicated query.
Finally, create a Var Number of Baskets With No Pears variable to count the IDs from your original query where the detail variable you just created is null
=Count([Query 1].[ID]) Where (IsNull([Var Query 2 Item]))
There you have it.

MySQL - Is it possible to sort data from one table based on the presence of data in another?

I have a table that I want to be able to sort based on the existence of data in another, related table, but I'm not sure what I want to do is possible in a single query.
For example, say I have a Products table and a Notifications table. Each table has a bunch of columns, but the important ones for this purpose is an Active column, and a foreign key in the Notifications table that references the Products table. Each row in the Products table may be referenced 0 to N times in the Notifications table.
Products Notifications
ProductID | Active NotificationID | ProductID | Active | Type
----------+------- ---------------+-----------+--------+-----
1 | 1 1 | 2 | 1 | 2
2 | 1 2 | 3 | 0 | 1
3 | 1 3 | 3 | 1 | 1
4 | 1 4 | 5 | 1 | 1
5 | 1 5 | 3 | 1 | 1
One use case I'd like to support is to sort the data from the Products table based on whether or not there is an active Notification of a particular Type (Type=1) for the Product. So in the above example, Products 3 and 5 to be collated first or last, but all five products should still be in the result set.
I haven't been able to figure out a way to manage this in a single SELECT statement. I can easily pull just the Products that do or don't have an active Notification of a certain type, but I can't figure out a way to get them all at once and sort them based on that. Is it possible or do I just need to run a couple of separate queries?
What you want is accomplished through a join and aggregation. I would suggest summarizing the notifications table as a subquery to get what you want:
select p.*
from products p left join
(select productId, count(*) as cnt
from notifications n
where active = 1
group by productid
) n
on p.productid = n.productid
order by (n.productid is not null) desc;
This structure gives you the flexibility of using the existence (as shown above), or the count, or including the count in the select list.

Querying entries by IDs aggregated by two different tables

I have the following table structure
table object_to_profile
objectID | profileID
1 | 1
2 | 1
3 | 1
2 | 2
table object_to_task
taskID | objectID | profileID
1 | 1 | 1
1 | 4 | 1
1 | 2 | 2
The table object_to_task is built the following way:
I show the user checkboxes, which basically represent the object_to_profile table.
The user can select objects out of the table and save them into the object_to_task table.
The Administrator can later remove the object from the table. But if the user has already selected some of the object from the profiles, it should be still visible to him. So I need a query to select all object that are currently in the profiles plus all objects that were in the table and have been selected by the user.
As you can see, objectID 4 is no longer in the object_to_profile table, but has been selected by the user.
What would be a way to the objectIDs together?
As far as i understand, you just need to union 2 result sets
select ObjectID from object_to_profile
union
select ObjectID from object_to_task where taskID = 1

Selecting multiple rows of data from a subtable along with the parent row table in MySQL

I have two tables in my database roughly laid out as below
Client
id | other data
1 | data 1
2 | data 2
3 | data 3
4 | data 4
Employee assigned
id | clientid | employee
1 | 1 | Fred
2 | 1 | Jim
3 | 3 | Peter
4 | 4 | Fred
5 | 4 | Peter
6 | 4 | James
Is there a way to return the client table with all of the employee records from the employee table? Ideally I would want both the id of the row and the employee name so I don't think I can use GROUP_CONCAT to collect more than one column. There is also no guarantee that there will always be an entry for each client in the employee table so it would need to return an empty/null result for those clients.
I have tried two ways to get this so far in php, both are pretty inefficient in one way or another.
(A) The first was to effectively make a new database connection half way through the first one to return the list of employees associated with that client id but obviously that results in a significant number of database connections being made for just one query.
(B) The second was to pull the entire employee table into an array at the beginning of the code and search through that array to pull out the rows relating to that client id which then have the employee name and row id in. Over time this is going to end up with a pretty large array being dumped into php instantly.
Is there some way of pulling this out using just a single SQL query? I'm not all that fussed how the data would come out as I am sure I could sort through it in the php at the other end, but perhaps something along the lines of
Results
id | other data | employees
1 | data 1 | 1,Fred;2,Jim
2 | data 2 |
3 | data 3 | 3,Peter
4 | data 4 | 4,Fred;5,Peter;6,James
If this has been asked before somewhere I apologise, but I have been searching around a bit over the last week and haven't found all that much to help.
SELECT e.*, c.other_data FROM Employee e
INNER JOIN Client c ON e.client_id = c.id
So, what you end up with is all the information from both tables grabbed in one query. So, the data would be:
id client_id Employee other_data
1 1 Fred data 1
2 1 Jim data 1
3 3 Peter data 3
4 4 Fred data 4
5 4 Peter data 4
6 4 James data 4

How do you get the records from single dataset to display onto 4 corners of landscape page? [SSRS]

I am using Microsoft SQL Server Reporting Services 2005
I have a report that when printed I want to display a record in each of the 4 corners of a landscape page.
I am using a single Dataset that returns 1 to many records.
How do I accomplish this with a table or matrix?
For example if I had 6 records in my dataset:
Page 1
|---------------------|
| record 1 | record 2 |
|---------------------|
| record 3 | record 4 |
|---------------------|
Page 2
|---------------------|
| record 5 | record 6 |
|---------------------|
| [empty] | [empty] |
|---------------------|
So I have found a successful way to do this (with help from cdonner's suggestion), have 2 identical table templates and have one display all odd records and the other to display all even records.
This is what Design Mode looks like:
|-------------------|
| table 1 | table 2 |
|-------------------|
Then, what I did was on each tablerow of each table added the expressions to the Visibility > Hidden property of the tablerow:
For Odd Rows:
=RowNumber(Nothing) Mod 2 = 0
For Even Rows:
=RowNumber(Nothing) Mod 2 = 1
The only way I can think of is by using subreports, one showing all even rows, the other one showing all odd rows.
To add Groups to Jon's answer, place tables 1 and 2 within a parent table which performs the grouping:
table-parent
group-row-header // header text..?
group-row-footer // group name is important for below
rectangle
table-child-1 | table-child-2 | etc // =RowNumber("my-group-name")
Note RowNumber must be based on the group so that it resets with each loop.