I have a table as such:
id entity_id first_year last_year sessions_attended age
1 2020 1996 2008 3 34.7
2 2024 1993 2005 2 45.1
3 ... ... ...
id is auto-increment primary key, and entity_id is a foreign key that must be unique for the table.
I have a query that calculates first and last year of attendance, and I want to be able to update this table with fresh data each time it is run, only updating the first and last year columns:
This is my insert/update for "first year":
insert into my_table (entity_id, first_year)
( select contact_id, #sd:= year(start_date)
from
( select contact_id, event_id, start_date from participations
join events on participations.event_id = events.id where events.event_type_id = 7
group by contact_id order by event_id ASC) as starter)
ON DUPLICATE KEY UPDATE first_year_85 = #sd;
I have one similar that does "last year", identical except for the target column and the order by.
The queries alone return the desired values, but I am having issues with the insert/update queries. When I run them, I end up with the same values for both fields (the correct first_year value).
Does anything stand out as the cause for this?
Anecdotal Note: This seems to work on MySQL 5.5.54, but when run on my local MariaDB, it just exhibits the above behavior...
Update:
Not my table design to dictate. This is a CRM that allows custom fields to be defined by end-users, I am populating the data via external queries.
The participations table holds all event registrations for all entity_ids, but the start dates are held in a separate events table, hence the join.
The variable is there because the ON DUPLICATE UPDATE will not accept a reference to the column without it.
Age is actually slightly more involved: It is age by the start date of the next active event of a certain type.
Fields are being "hard" updated as the values in this table are being pulled by in-CRM reports and searches, they need to be present, can't be dynamically calculated.
Since you have a 'natural' PK (entity_id), why have the id?
age? Are you going to have to change that column daily, or at least monthly? Not a good design. It would be better to have the constant birth_date in the table, then compute the ages in SELECT.
"calculates first and last year of attendance" -- This implies you have a table that lists all years of attendance (yoa)? If so, MAX(yoa) and MIN(yoa) would probably a better way to compute things.
One rarely needs #variables in queries.
Munch on my comments; come back for more thoughts after you provide a new query, SHOW CREATE TABLE, EXPLAIN, and some sample data.
Related
I have two tables: Orders that contains available orders and ExecutorsOfferOffers that contains offers by concrete user for specific order:
The order can be in four statuses: accepted, canceled, finished. Inside ExecutorsOfferOffers we have history of rows when user can accept, reject and complete the order (field status).
At the same time table Orders also has status field to show the current status of order. I confused how to be, move executor_id as external key to Orders table among status. Or store them in ExecutorsOfferOffers. And retrieve the status the order by selecting onw row ordered by id from ExecutorsOfferOffers.
In this case I faced with problem when user can accept, then cancel order (insert two rows in ExecutorsOfferOffers with different statuses).
If I understand correctly:
ExecutorsOrderOffers contains the history of user requests to change the status of the order.
Orders contains the current status of the order.
One Order can have many ExecutorsOrderOffers.
They're not recording the same data.
This information is not necessarily the same. Just because a User requested an order be cancelled does not mean it is cancelled; someone might need to make a phone call or an API might need to be contacted. Perhaps you should leave the status decoupled.
This leaves more flexibility for the business logic to determine the relationship between ExecutorsOrderOffers and Orders.
Use a join table to record the Order status.
Status flags get messy. You have to remember to add them to every where clause, and they make indexing complicated. Instead, consider using a join table to record the status of an order.
-- One for each status.
create table AcceptedOrders (
Order_Id int not null
foreign key(Order_Id) references Orders(Id)
);
Add a timestamp to ExecutorsOrderOffers.
IDs are not a surrogate for timestamps, and you're probably going to want to know when a user made a change; add a Created_At timestamp.
Add an index on ExecutorsOrderOffers(Created_At, Orders_ID)
Index Created_At with Orders_ID in that order. This will cover searches and order by for Created_At as well as when combined with an Orders_ID.
The foreign key index already covers search by Orders_ID alone.
Now you can efficiently look up the latest user request to change the status of an order.
I'm setting up a system where for every user (1000+), I want to add a set of values every single day.
Hypotetically:
A system where I can log when Alice and Bob woke up and what they had for dinner on the August 1st 2019 or 2024.
Any suggestions on how to best structure the database tables?
A person table with a primary person ID?
rows: n
A date table with a primary date ID?
rows: m
And a personDate table the person ID and date ID as foreign keys?
rows n x m
I don't think u need a date table unless u want to use it to make specific queries easier. Such as left join against the date to see what days you are missing events. Nevertheless, I would stick to the DATE or DATETIME as the field and avoid making a separate surrogate foreign key. It won't save any space and will potentially perform worse and will be more difficult to use for the developer.
This seems simple and fine to me. I wouldn't worry too much about the performance based upon the number of elements alone. You can insert a billion records with no problem and that implies a very large site.
Just don't insert records if the event didn't happen. In other words you want your database to grow in relation to the real usage. Avoid growth based upon phantom events and you should be okay.
person
person_id
action
action_id
personAction
person_id
action_id
action_datetime
I am new to Access and I am looking for a solution that is beyond the ability of the others in my company and may be beyond what access can do.
I have the following fields.
Date: Last Name: First Name: Test1: Test2: Test3:
I am looking for the following to happen.
On any single date a user may test multiple times.
If the user passes all three tests do not show any records with fails or any duplicate passes.
If the user fails any of the three tests, but has multiple failed records only show one.
If the user has the statement "NotUsed" in any field, but a pass in any other keep a single record for that date.
Thank You,
First, you need a primary key column in order to be able to easily and unambiguously identify each record. In Access this is easily achievable with a Autonumber column. Also, in the table designer, click the key symbol for this column. This creates a primary key index. A primary key is a must for every table.
Let us call this column TestID and let's assume that the table is named tblTest.
The problem is that your condition refers to several records; however, SQL expects a WHERE clause that specifies the conditions for each single record. So let’s try to reformulate the conditions:
Keep the record with the most passes for each user.
Keep records with "NotUsed" in any test field.
The first condition can be achieved like this:
SELECT First(TestID)
FROM
(SELECT TestID, [Last Name], [First Name] FROM tblTest
ORDER BY IIf(Test1='pass',1,0) + IIf(Test2='pass',1,0) + IIf(Test3='pass',1,0) DESC)
GROUP BY [Last Name], [First Name]
This gives you the TestID for each user with the most passes. Now, this is not the final result yet, but you can use this query as a subquery in the final query
SELECT * FROM tblTest
WHERE
Test1='NotUsed' OR Test2='NotUsed' OR Test3='NotUsed' OR
TestID IN ( <place the first query here...> )
Is this what you had in mind?
Another thought is about normalization. Your table is not normalized. You are using your table like an Excel sheet. As your database grows you'll get more and more into trouble.
You have two kinds of non-normalization.
One relates to the fact that each user's first name and last name might occur in several records. If, in future, you want to add more columns, like user address and phone number, then you will have to repeat these entries for each user record. It will become increasingly difficult to keep this information synchronized over all the records. The way to go is to have at least two tables: a user table and a test table where the user table has a UserID as primary key and the test table has this UserID as foreign key. Now a user can have many test records but still always has only one unique user record.
The other one (non-normalization) occurs because you have 3 Test fields in a single record. This is less of a problem if your tests always have the same structure and always require 3 tests per date, but even here you have to fall back to the "NotUsed" entries. There are several ways to normalize this, because a database can have different degrees of normalization. The tree ways:
Only one test table with the fields: TestID (PK), UserID (FK), Date, Result, TestNumber.
A test day table with the fields: TestDayID (PK), UserID (FK), Date + a test result table with the fields: TestResultID (PK), TestDayID (FK), Result, TestNumber
Then you can combine the two previous with this addition: Instead of having a TestNumber field, introduce a lookup table containing information on test types with the fields: TestTypeID (PK), TestNo, Description and in the other tables replace the column TestNumber with a column TestTypeID (FK).
See: How to normalize a table using Access - Part 1 of 4 or look at many other articles on this subject.
I am using MySQL workbench to manage my a database that was handed down to me for a development task. Unfortunately, the schema is a nightmare: no primary keys for numerous tables, lots of column duplication, etc.
First off, I wanted to add some uniqueness so that I can begin normalizing somehow. I have a 'students' table where a student (with an ID) works on a project that belongs to a specific term (Fall 2014, Spring 2015, etc.)
Since the same student can work on the same project two semesters in a row for whatever reason, that only way to tell them apart would be to have a (student ID, term) PK. So I actually do need that composite PK.
How might I alter the existing tables and set a composite PK?
EDIT:
To clarify: the schema contains a users table with actual student information (First/Last name, Email, Term). The students table would more aptly be named projects, as it references only the students by ID and then lists the project they worked on, in the semester that they worked on it. So at the very least, students.id would also be a FK from users.
I know the above doesn't quite make any sense; I'm just trying to keep this to one step at a time because the application depends on the schema and I don't want to introduce any new bugs at this point.
To clarify even further, here is how the users and students tables look like:
students
id project termInitiated ...
20 XYZ Summer 2013
20 XYZ Fall 2013
23 ABC Fall 2013
24 ABC Fall 2014
...
users
studentId firstName lastName termInitiated
20 A AA Summer 2013
20 A AA Fall 2013
23 Z ZZ Fall 2013
24 Y YY Fall 2014
...
Unfortunately, due to the way it is setup, I cannot have studentId be a PK by itself as the same student could be working on the same project multiple semesters in a row.
The best fix to this would be a globally unique identifier that could refer to the same student in different terms, but this would introduce a huge amount of bugs right now that I do not have the time to fix. Thus, I think that a composite PK would be the best solution given my limitations.
You may need to grant yourself the alter privilege if the composite key is not being added take a look at this: https://kb.mediatemple.net/questions/788/How+do+I+grant+privileges+in+MySQL%3F#dv
Here is adrian's link :ALTER TABLE to add a composite primary key
My suggestion is that, add a new field in your table for primary key with the unique combination of two fields.
For example in your case, add a field suppose pid in students table:
ALTER TABLE students
ADD pid VARCHAR(100) UNIQUE PRIMARY KEY;
And then update this table:
UPDATE students SET pid=CONCAT(id, '-', termInitiated);
So you will have unique combination of id and termInitiated in pid field.
You can use it as primary key and if you want to select it or join it with other table, you can reference it with combination of two field.
For example,
If you want to join student table with users, you can join it like:
SELECT * FROM users
INNER JOIN students
ON CONCAT(users.studentId, '-', termInitiated) = student.pid);
I hope this will work for you.
Please correct/suggest me, I am wrong.
Thank you.
We have an issue-tracking system for our software. Yesterday my boss gave me the task of finding all issues in the issue table submitted by this certain guy with an ID of 2992:
issue table:
issue_id (int)
submitter_id (int)
...other fields
Then for each issue in that result set I had to look at another table to find who was subscribed to it:
issue_subscribers table:
issue_id (int) [primary key to issue table]
subscriber_id (int)
...other fields
I had these ID numbers (3247, 4748, 7430, 8429) which represent other users, and if any of them were NOT subscribed, I had to add them as subscribers to the issue. This means simply adding a new row to issue_subscribers table.
This was way over my head. I ended up doing this with 3 different queries in a Java JDBC program instead of trying to figure it out with pure SQL. But now I'm curious how it could be done. Is this a simple procedure for professional SQL guys? Is it possible to write a single query to do this? How would it be done?
Supposing:
subscriber_id is a foreign key to some table that hold all possible subscribers.
You only need to do this with issue 2992 and subscribers 3247, 4748, 7430 and 8429.
You could write following SQL query:
Insert Into issue_subscribers
(
issue_id,
subscriber_id
-- and other fields if necessary
)
(
Select 2992 issue_id,
subscriber_id
-- and other fields if necessary
From subscribers subs -- table that holds all possible subscribers
Where subscriber_id In (3247, 4748, 7430, 8429)
And Not Exists (Select 1
From issue_subscribers iss
Where issue_id = 2992
And iss.subscriber_id = subs.subscriber_id)
);
In case you would need to use it for other issues and subscribers you would need to change the ids to parameters, and specify the subscriber_ids of the in condition some other way (perhaps a subselect of some kind).