How to implement Auto_Increment per User, on the same table? - database

I would like to have multiple users that share the same tables in the database, but have one auto_increment value per user. I will use an embedded database, JavaDB and as what I know it doesn't support this functionality. How can I implement it?
Should I implement a trigger on inserts that lookup the users last inserted row, and then add one, or are there any better alternative? Or is it better to implement this in the application code?
Or is this just a bad idea? I think this is easier to maintain than creating new tables for every user.
Example:
table
+----+-------------+---------+------+
| ID | ID_PER_USER | USER_ID | DATA |
+----+-------------+---------+------+
| 1 | 1 | 2 | 3454 |
| 2 | 2 | 2 | 6567 |
| 3 | 1 | 3 | 6788 |
| 4 | 3 | 2 | 1133 |
| 5 | 4 | 2 | 4534 |
| 6 | 2 | 3 | 4366 |
| 7 | 3 | 3 | 7887 |
+----+-------------+---------+------+
SELECT * FROM table WHERE USER_ID = 3
+----+-------------+---------+------+
| ID | ID_PER_USER | USER_ID | DATA |
+----+-------------+---------+------+
| 3 | 1 | 3 | 6788 |
| 6 | 2 | 3 | 4366 |
| 7 | 3 | 3 | 7887 |
+----+-------------+---------+------+
SELECT * FROM table WHERE USER_ID = 2
+----+-------------+---------+------+
| ID | ID_PER_USER | USER_ID | DATA |
+----+-------------+---------+------+
| 1 | 1 | 2 | 3454 |
| 2 | 2 | 2 | 6567 |
| 4 | 3 | 2 | 1133 |
| 5 | 4 | 2 | 4534 |
+----+-------------+---------+------+

If you can guarantee that there will only be one session per user, then it would be pretty safe to do. If a user can have more than one session then whether you do this in a trigger or in the application code you will need to take an exclusive table lock to make sure that the session you are in is the only one to get that next number.
But don't go for a table per user. That would make your sql really ugly and prevent any sort of sql plan sharing.
You may be better served by using a timestamp instead of a serial number.

Related

MSSQL recursive query to find furthest parent

We have a db structure where each company has a parent company defined. What we want to do is walk up the structure from a given start point until the next 'most-parent' company is found and pull what that users assignment is to that 'most-parent' company. Below is a mock example.
+===================+ +=======+ +=============+
| Company | | User | | UserAccess |
+===================+ +=======+ +=============+
| id | | id | | id |
| Name | | Name | | fkUserId |
| fkParentCompanyId | +=======+ | fkCompanyId |
+===================+ | AccessLevel |
+=============+
+=======+
|Company|
+=============================================+
| id | Name | fkParentCompanyId |
+=============================================+
| 1 | ABC Corp | 1 |
| 2 | Outside Company | 1 |
| 3 | Inside Company | 1 |
| 4 | My Company | 3 |
| 5 | Other LLC | 4 |
| 6 | Yet Another Comp | 5 |
+=============================================+
+====+
|User|
+======================+
| id | Name |
+======================+
| 1 | Mike |
| 2 | Jackie |
| 3 | Sam |
+======================+
+==========+
|UserAccess|
+=================================================+
| id | fkUserId | fkCompanyId | AccessLevel |
+=================================================+
| 1 | 1 | 1 | Administrator |
| 2 | 2 | 1 | User |
| 3 | 3 | 1 | Administrator |
| 4 | 3 | 3 | Parent |
| 5 | 3 | 4 | Parent |
| 6 | 3 | 5 | Parent |
| 7 | 3 | 6 | Parent |
+=================================================+
So take 'Same', user.id == 3. I want to do a query that finds the nearest "not-Parent" relationship when given a starting Company.id along with Sam's User.id. Next is what I'm looking to get from the given inputs.
Inputs: User.id = 3, Company.id = 6
Output: Administrator
Inputs: User.id = 3, Company.id = 5
Output: Administrator
Inputs: User.id = 3, Company.id = 4
Output: Administrator
Inputs: User.id = 2, Company.id = 1
Output: User
I've been looking at recursive queries using the CTE model, having some difficulty understanding what's it's really doing and thus not yet able to translate that model into something that would work for the above example.
Any guidance would be greatly appreciated.
Update
Been working on CTE in SSMS and feel like I'm getting close... Here is an example query that I'm trying, but not getting the result I expect...
Here I'm trying to do a recursive CTE on Sam # "Yet Another Comp". What I want is a list of Sams access up the chain.
with cte(UserId, CompanyId, UserAccess, ParentCompanyId)
as
(
select
[UserId],
[CompanyId],
[UserAccess],
[ParentCompanyId]
from [UserAccess]
where [UserId] = 3 and [CompanyId] = 6
union all
select
[UserAccess].[UserId],
[UserAccess].[CompanyId],
[UserAccess].[AccessLevel],
[cte].[ParentCompanyId]
from [UserAccess]
join [cte] on [UserAccess].[ParentCompanyId] = [cte].[CompanyId]
where [UserAccess].[UserId] = 3 [UserAccess].[CompanyId] != 6
)
select * from cte
I'm expecting this:
+===+
|cte|
+==========================================================+
| UserId | CompanyId | UserAccess | ParentCompanyId |
+==========================================================+
| 3 | 6 | Parent | 5 |
| 3 | 5 | Parent | 4 |
| 3 | 4 | Parent | 3 |
| 3 | 3 | Parent | 1 |
| 3 | 1 | Administrator | 1 |
+==========================================================+
But what I'm actually getting is this:
+===+
|cte|
+==========================================================+
| UserId | CompanyId | UserAccess | ParentCompanyId |
+==========================================================+
| 3 | 6 | Parent | 5 |
+==========================================================+
The recursive query isn't pulling additional rows into the table. So I commented out the where statement on the recursive query, expecting to get a max recursion error and see a blip of all of the results. But no, still just get the single row back.

Create materialized view from multiple tables with identical schemas

I am trying create a materialized view in Redshift.
I have 100 tables of the form
user_1
user_2
...
user_100
Each table has the same schema. For example:
user_1
| id | user_id | date | expense |
|----|---------|----------|---------|
| 1 | 1 | 20200521 | 200 |
| 2 | 2 | 20200601 | 100 |
| 3 | 1 | 20200603 | 90 |
user_2
| id | user_id | date | expense |
|----|---------|----------|---------|
| 1 | 1 | 20200521 | 250 |
| 2 | 3 | 20200204 | 10 |
| 3 | 2 | 20200403 | 50 |
What I want to do is to create a materialized view which has all the rows from all 100 tables.
The objective is to run a queries to calculate the sum(expense) for given user_id between certain dates.
So my materialized view will be something like this:
user_1
| id | user_id | date | expense |
|----|---------|----------|---------|
| 1 | 1 | 20200521 | 200 |
| 2 | 2 | 20200601 | 100 |
| 3 | 1 | 20200603 | 90 |
| 4 | 1 | 20200521 | 250 |
| 5 | 3 | 20200204 | 10 |
| 6 | 2 | 20200403 | 50 |
I am having trouble with the CREATE query for this view.
Any guidance on the query to create this view is appreciated.
Thank you.
How about UNIONing the tables?
Keep in mind the difference between UNION (does implicit distinct) and UNION ALL which just combines rows from two tables as they come.
CREATE MATERIALIZED VIEW users
AS
SELECT * FROM user_1 UNION ALL
SELECT * FROM user_2 UNION ALL
SELECT * FROM user_3 UNION ALL
...
SELECT * FROM user_100

Records that have not been accessed by a different table

I have a users table, videos table and actions table. When a user views a video, an actions record gets created with both their ids and some information. I want to get the Y videos not accessed by X users.
Users table
|---------------------|------------------|---------------------|
| ID | Name | account_id |
|---------------------|------------------|---------------------|
| 1 | user 1 | 1 |
|---------------------|------------------|---------------------|
| 2 | user 2 | 1 |
|---------------------|------------------|---------------------|
| 3 | user 3 | 1 |
|---------------------|------------------|---------------------|
Videos table
|---------------------|------------------|---------------------|
| ID | Name | account_id |
|---------------------|------------------|---------------------|
| 1 | video 1 | 1 |
|---------------------|------------------|---------------------|
| 2 | video 2 | 1 |
|---------------------|------------------|---------------------|
| 3 | video 3 | 1 |
|---------------------|------------------|---------------------|
Actions table
|---------------------|------------------|---------------------|
| user_id | video_id | account_id |
|---------------------|------------------|---------------------|
| 1 | 3 | 1 |
|---------------------|------------------|---------------------|
| 1 | 2 | 1 |
|---------------------|------------------|---------------------|
| 3 | 1 | 1 |
|---------------------|------------------|---------------------|
| 3 | 2 | 1 |
|---------------------|------------------|---------------------|
Desired Output:
|---------------------|------------------|
| user name | video name |
|---------------------|------------------|
| user 1 | video 1 |
|---------------------|------------------|
| user 2 | video 1 |
|---------------------|------------------|
| user 2 | video 2 |
|---------------------|------------------|
| user 2 | video 3 |
|---------------------|------------------|
| user 3 | video 3 |
|---------------------|------------------|
Edit: I think is worth mentioning that there is also a foreign key attached to all of the columns called account_id. for the example we'll assume they all have the same account_id.
demo:db<>fiddle
SELECT
u.name,
v.name
FROM
users u CROSS JOIN videos v
WHERE (u.id, v.id) NOT IN (
SELECT user_id, video_id FROM actions
)
Note: This expected result seems really unhandy. On bigger data sets you may get a really huge output!
First you have to create a CROSS JOIN which joins every user record agains every video record. Afterwards you can filter the existing combinations using the action table.

Find the newest entry of a crosstable per record?

I have three tables:
My products with their IDs and their features.
is a table with treatments of my products with a treatment-ID, a method, and a date. The treatments are done in batches of many products so there is a crosstable
with the products IDs and the treatment IDs and a bool value for the success of the treatment.
Each product can undergo many different treatments so there is a many-to-many relation. I now want to add to the product table (1.) for every product a value that shows the method of its most recent successful treatment if there is any.
I made a query that groups the crosstable's entries by product-ID but I don't know how to show the method and date of it's last treatment.
table 1:
| productID | size | weight | height | ... |
|-----------|:----:|-------:|--------|-----|
| 1 | 13 | 16 | 9 | ... |
| 2 | 12 | 17 | 12 | ... |
| 3 | 11 | 15 | 15 | ... |
| ... | ... | ... | ... | ... |
table 2:
| treatmentID | method | date |
|-------------|:--------:|-----------:|
| 1 | dye blue | 01.02.2016 |
| 2 | dye red | 01.02.2017 |
| 3 | dye blue | 01.02.2018 |
| ... | ... | ... |
table 3:
| productID | treatmentID | success |
|-----------|:-----------:|--------:|
| 1 | 1 | yes |
| 1 | 2 | yes |
| 1 | 3 | no |
| ... | ... | ... |
I need table 1 to be like:
table 1:
| productID | size | weight | height | latest succesful method |
|-----------|:----:|-------:|--------|-------------------------|
| 1 | 13 | 16 | 9 | dye red |
| 2 | 12 | 17 | 12 | ... |
| 3 | 11 | 15 | 15 | ... |
| ... | ... | ... | ... | ... |
My query:
SELECT table3.productID, table2.method
FROM table2 INNER JOIN table3 ON table2.treatmentID = table3.treatmentID
GROUP BY table3.productID, table2.method
HAVING (((table3.productID)=Max([table2].[date])))
ORDER BY table3.productID DESC;
but this does NOT show only one (the most recent) entry but all of them.
Simplest solution here would be to write either a subquery within your sql, or create a new query to act as a subquery(it will look like a table) to help indicate(or elminate) the records you want to see.
Using similar but potentially slightly different source data as you only gave one example.
Table1
| ProductID | Size | Weight | Height |
|-----------|------|--------|--------|
| 1 | 13 | 16 | 9 |
| 2 | 12 | 17 | 12 |
| 3 | 11 | 15 | 15 |
Table2
| TreatmentID | Method | Date |
|-------------|------------|----------|
| 1 | dye blue | 1/2/2016 |
| 2 | dye red | 1/2/2017 |
| 3 | dye blue | 1/2/2018 |
| 4 | dye yellow | 1/4/2017 |
| 5 | dye brown | 1/5/2018 |
Table3
| ProductID | TreatmentID | Success |
|-----------|-------------|---------|
| 1 | 1 | yes |
| 1 | 2 | yes |
| 1 | 3 | no |
| 2 | 4 | no |
| 2 | 5 | yes |
First order of business is to get the max(dates) and productIds of successful treatments.
We'll do this by aggregating the date along with the productIDs and "success".
SELECT Table3.productid, Max(Table2.Date) AS MaxOfdate, Table3.success
FROM Table2 INNER JOIN Table3 ON Table2.treatmentid = Table3.treatmentid
GROUP BY Table3.productid, Table3.success;
This should give us something along the lines of:
| ProductID | MaxofDate | Success |
|-----------|-----------|---------|
| 1 | 1/2/2018 | No |
| 1 | 1/2/2017 | Yes |
| 2 | 1/4/2017 | No |
| 2 | 1/8/2017 | Yes |
We'll save this query as a "regular" query. I named mine "max", you should probably use something more descriptive. You'll see "max" in this next query.
Next we'll join tables1-3 together but in addition we will also use this "max" subquery to link tables 1 and 2 by the productID and MaxOfDate to TreatmentDate where success = "yes" to find the details of the most recent SUCCESSFUL treatment.
SELECT table1.productid, table1.size, table1.weight, table1.height, Table2.method
FROM ((table1 INNER JOIN [max] ON table1.productid = max.productid)
INNER JOIN Table2 ON max.MaxOfdate = Table2.date) INNER JOIN Table3 ON
(Table2.treatmentid = Table3.treatmentid) AND (table1.productid = Table3.productid)
WHERE (((max.success)="yes"));
The design will look something like this:
Design
(ps. you can add queries to your design query editor by clicking on the "Queries" tab when you are adding tables to your query design. They act just like tables, just be careful as very detailed queries tend to bog down Access)
Running this query should give us our final results.
| ProductID | Size | Weight | Height | Method |
|-----------|------|--------|--------|-----------|
| 1 | 13 | 16 | 9 | dye red |
| 2 | 12 | 17 | 12 | dye brown |

Count rows which has the same ID and display on the table

This is the original table:
| ID | Card_No |
|----+---------|
| 1 | 6453671 |
| 1 | 8795732 |
| 1 | 9948495 |
| 2 | 7483009 |
| 2 | 1029001 |
| 3 | 7463094 |
Is it possible to make it like this? Which will be adding a calculated column the the original table?
| ID | Card_No | Total |
|----+---------|-------|
| 1 | 6453671 | 3 |
| 1 | 8795732 | 3 |
| 1 | 9948495 | 3 |
| 2 | 7483009 | 2 |
| 2 | 1029001 | 2 |
| 3 | 7463094 | 3 |
I'm using Microsoft Access, and I've tried code like this:
SELECT ID, COUNT (*) AS Total FROM Table GROUP BY ID
But I did not get the result I want.
First of all, saving the calculated value back into table is not only unnecessary but bad design.
Options:
build a report that counts records with an expression in textbox
build aggregate query then another query joining aggregate query to the table
DCount() domain aggregate function in query

Resources