Here is the issue: I have 4 tables in a DB. one is "calls" and the other 3 are the support teams "IT","Maintenance","Engineering". When a row is created in the "calls" table there is a field named" Support team" and there are 3 possible options for this field it, maintenance, and engineering. I need to be able to email these teams based on what team has been requested in the "calls" table. All of the email info is stored in the individual team's table. I hope this makes sense. If not I can diagram the issue.
Create 3 string variables to go into support_team field of the calls table: it, maintenance, engineering.
Let the variables have the same name as the database tables it, maintenance and engineering.
After inserting a new record in the calls table, use this
$team = "Select calls.support_team from calls where id = $last_id ";
"Select * from $team ";
Where $last_id is the id of the recently inserted record in the calls table.
Since $team gets the name of the tables: id, maintenance or engineering; the second line of code just gets the names of team members.
Since the tables are limited you could do a bunch of left joins:
SELECT * FROM calls
LEFT JOIN team_it ON calls.`support team` = 'it' AND calls.id = team_it.id
... etc
I didn't know what the join conditions are, so I guessed the calls.id = team_it.id
If the three tables already have a "foreign key" to calls, you can just left join on that instead.
Related
I need help with this mysql query that executes too long or does not execute at all.
(What I am trying to do is a part of more complex problem, where I want to create PHP cron script that will execute few heavy queries and calculate data from the results returned and then use those data to store it in database for further more convenient use. Most likely I will make question here about that process.)
First lets try to solve one of the problems with these heavy queries.
Here is the thing:
I have table: users_bonitet. This table has fields: id, user_id, bonitet, tstamp.
First important note: when I say user, please understand that users are actually companies, not people. So user.id is id of some company, but for some other reasons table that I am using here is called "users".
Three key fields in users_bonitet table are: user_id ( referencing user.id), bonitet ( represents the strength of user, it can have 3 values, 1 - 2 - 3, where 3 is the best ), and tstamp ( stores the time of bonitet insert. Every time when bonitet value changes for some user, new row is inserted with tstamp of that insert and of course new bonitet value.). So basically some user can have bonitet of 1 indicating that he is in bad situation, but after some time it can change to 3 indicating that he is doing great, and time of that change is stored in tstamp.
Now, I will just list other tables that we need to use in query, and then I will explain why. Tables are: user, club, club_offer and club_territories.
Some users ( companies ) are members of a club. Member of the club can have some club offers ( he is representing his products to the people and other club members ) and he is operating on some territory.
What I need to do is to get bonitet value for every club offer ( made by some user who is member of a club ) but only for specific territory with id of 1100000; Since bonitet values are changing over time for each user, that means that I need to get the latest one only. So if some user have bonitet of 1 at 21.01.2012, but later at 26.05.2012 it has changed to 2, I need to get only 2, since that is the current value.
I made an SQL Fiddle with example db schema and query that I am using right now. On this small database, query is working what I want and it is fast, but on real database it is very slow, and sometimes do not execute at all.
See it here: http://sqlfiddle.com/#!9/b0d98/2
My question is: am I using wrong query to get all this data ? I am getting right result but maybe my query is bad and that is why it executes so slow ? How can I speed it up ? I have tried by putting indexes using phpmyadmin, but it didn't help very much.
Here is my query:
SELECT users_bonitet.user_id, users_bonitet.bonitet, users_bonitet.tstamp,
club_offer.id AS offerId, club_offer.rank
FROM users_bonitet
INNER JOIN (
SELECT max( tstamp ) AS lastDate, user_id
FROM users_bonitet
GROUP BY user_id
)lastDate ON users_bonitet.tstamp = lastDate.lastDate
AND users_bonitet.user_id = lastDate.user_id
JOIN users ON users_bonitet.user_id = users.id
JOIN club ON users.id = club.user_id
JOIN club_offer ON club.id = club_offer.club_id
JOIN club_territories ON club.id = club_territories.club_id
WHERE club_territories.territory_id = 1100000
So I am selecting bonitet values for all club offers made by users that are members of a club and operate on territory with an id of 1100000. Important thing is that I am selecting club_offer.id AS offerId, because I need to use that offerId in my application code so I can do some calculations based on bonitet values returned for each offer, and insert data that was calculated to the field "club_offer.rank" for each row with the id of offerId.
Your query looks fine. I suspect your query performance may be improved if you add a compound index to help the subquery that finds the latest entry from users_botinet for each user.
The subquery is:
SELECT max( tstamp ) AS lastDate, user_id
FROM users_bonitet
GROUP BY user_id
If you add (user_id, tstamp) as an index to this table, that subquery can be satisfied with a very efficient loose index scan.
ALTER TABLE users_bonitet ADD KEY maxfinder (user_id, tstamp);
Notice that if this users_botinet table had an autoincrementing id number in it, your subquery could be refactored to use that instead of tstamp. That would eliminate the possibility of duplicates and be even more efficient, because there's a unique id for joining. Like so.
FROM users_botinet
INNER JOIN (
SELECT MAX(id) AS id
FROM users_botinet
GROUP BY user_id
) ubmax ON users_botinet.id = ubmax.id
In this case your compound index would be (user_id, id.
Pro tip: Don't add lots of indexes unless you know you need them. It's a good idea to read up on how indexes can help you. For example. http://use-the-index-luke.com/
Okay so im new to databases, and have created a site with a users table, and i also hace a list table, where suers can insert list items, however when they log in everyones list is appearing, how can i link the user table to the lists table, is it creating the same field in each one and using a foreign key? Sorry I am very new to this. Appreciate any help
I think you can just use user_id on both tables to fix this. Let me give an example:
Table A (user_id, username, password)
Table B (list_item_id, user_id , any_other_attribute)
When you design your tables like this a simple sql call will do what you need like:
SELECT 'list_item_id','any_other_attribute' FROM Table B Where user_id=$user_id
Where $user_id is the user_id of the one's who loginned your system.
Also by your question, i suggest you to read about these : 'sessions' , 'sql queries' , 'generating sql query results' on your choice of programming language.
It calls MANY MANY relationnship. There mus be 1 table with fields user_id and field_id that will join this 2 tables
I have three tables, the first is a table storing applications, the second is a table storing different online forms (different types of applications), the third is a table that stores actual form data:
TABLE applications=========
-applicationID (PK)
-formID (FK)
-formRecordID
====================
TABLE forms=========
-formID (PK)
-formName
-tableName (could be 'form_businessLicense','eventLicense',etc)
====================
TABLE form_businessLicense=====
-recordID (PK)
-dateSubmitted
-(a whole bunch of other data)
===============================
"formRecordID" points to "recordID" in "form_businessLicense" or "eventLicense". Since it could reference any table, it can't be a foreign key. So instead I grab the tableName from the "forms" table, then build a query to get all the application data from, say "form_businessLicense".
So I need to get data from, say, all applications plus a bit of data from the application form filled out (ex:form_businessLicense). I'm just going to paste my code (I'm actually querying all applications in a given set of IDs):
$applications = $this->selectAll(
"SELECT applicationID, formName, tableName, fieldIdentifier, formRecordID, dateSubmitted, DATE_FORMAT(dateSubmitted,'%c/%e/%Y') AS dateSubmittedFormat
FROM applications AS a
JOIN forms AS f
ON a.formID = f.formID
WHERE a.applicationID IN (".$applicationIDs.")
ORDER BY dateSubmitted ASC"
);
for($a=0;$a<count($applications);$a++){
$form = $this->select("SELECT ".$applications[$a]['fieldIdentifier']." AS identifierName
FROM ".$applications[$a]['tableName']."
WHERE recordID = ".$applications[$a]['formRecordID']
);
$applications[$a]['identifierName'] = $form['identifierName'];
}
Is there any way to merge these two queries into one so I don't have to loop over all results and run a separate query for each result? I feel like I could maybe do this with a JOIN but I'm not sure how to reference the "tableName" and "formRecordID" for use in the same SQL statement.
You need to apply join to three tables, and select count(PK) of third table while adding a group by clause for the PK of third table.
Note: PK used for Primary Key
I'm trying to record test/quiz scores in a database. What's the best method to do this when there might be a lot of tests and users?
These are some options I considered: should I create a new column for each quiz and row for users, or does this have its limitations? Might this be slow? Should i create a new row for each user & quiz? Should I stick to my original 'user' database and encode it in text?
Elaborating a little on the plan: JavaScript Quiz, submits score with AJAX, and a script sends it to the database. I'm new with php so i'm not sure about a good approach.
Any help would be greatly appreciated :) this is for a school science fair
I'd suggest 3 data tables in your database: students, tests, and scores.
Each student needs to have fields for an ID and whatever else (name, dob, etc) you want to record about them.
Tests should have fields for an ID and whatever else (name, date, weight, etc).
Scores should have the student ID, a test ID, and the score (any anything else).
This means you can query a student and join with the scores table to get all the student's scores. You can also join the test table these results to get labels put onto each score and calculate a grade based on scores and weight.
Alternately you can query for a test and join with the scores to get all the scores on a given test to get the class stats.
I would say create a database table, maybe one that lists all students(name, dob, student id), and then one for all tests(score, date, written by). Will only you access the db, or can your students access it too? If the latter is the case, you need to make sure the create accurate security or "views" to ensure the student can only see their own grades at a time (not everyone's).
Definitely do not create dynamic columns! (no column for each quiz). Also adding columns to user table (or generally any table) when they are not identifying the user(or generally any table item) is bad aproach...
This is pretty example of normalization, you should avoid storing any redundant rows. To do that you would create 3 tables and foreign keys to ensure scores are always referencing an existing user and quiz. E.g.:
users - id, nickname, name
quizzes - id, quizName, quizOtherData
scores - id, user_id (references users.id) , quiz_id , (ref. quizzes.id), score
And then add rows to scores table per user per quiz. Additionaly you could create UNIQUE key for columns user_id and quiz_id to disallow users to complete one quiz more times than one.
This will be fast and will not store redundant (unneeded extra) data.
To get results of quiz with id e.g. 4 and user info of people who's submitted this quiz, ordered from highest to lowest score, you would do query like:
SELECT users.*, scores.score
FROM scores RIGHT JOIN users ON(users.id=scores.user_id)
WHERE scores.quiz_id = 4
ORDER BY score DESC
Reason why I used RIGHT join here is because there might be users that didn't do this quiz, however every score always have an existing user&quiz (due to foreign keys
To get overall info of all users, quizes and scores you would do something like:
SELECT *
FROM quizzes
LEFT JOIN scores ON(quizzes.id=scores.quiz_id)
LEFT JOIN users ON(users.id=scores.user_id)
ORDER BY quizzes.id DESC, scores.score DESC, users.name ASC
BTW: If you are new to PHP (or anybody reading this), use PHP's PDO interface to communicate with your database :) AVOID functions like mysql_query, at least use mysqli_query, but for portability I would recommend stay with PDO.
I'm developing a reward system for our VLE which uses three separate technologies - JavaScript for most of the client-side/display processing, PHP to communicate with the database and MySQL for the database itself.
I've attached three screenshots of my "transactions" table. Its structure, a few example records and an overview of its details.
The premise is that members of staff award points to students for good behaviour etc. This can mean that classes of 30 students are given points at a single time. Staff have a limit of 300 points/week and there are around 85 staff currently accessing the system (this may rise).
The way I'm doing it at the moment, every "transaction" has a "Giver_ID" (the member of staff awarding points), a "Recipient_ID" (the student receiving the points), a category and a reason. This way, every time a member of staff issues 30 points, I'm putting 30 rows into the database.
This seemed to work early on, but within three weeks I already have over 12,000 transactions in the database.
At this point it gets a bit more complicated. On the Assign Points page (another screenshot attached), when a teacher clicks into one of their classes or searches for an individual student, I want the students' points to be displayed. The only way I can currently do this on my system is to do a "SELECT * FROM 'transactions'" and put all the information into an array using the following JS:
var Points = { "Recipient_ID" : "0", "Points" : "0" };
function getPoints (data) {
for (var i = 0; i < data.length; i++) {
if (Points[data[i].Recipient_ID]) {
Points[data[i].Recipient_ID] = parseInt(Points[data[i].Recipient_ID]) + parseInt(data[i].Points);
} else {
Points[data[i].Recipient_ID] = data[i].Points;
}
}
}
When logging in to the system internally, this appears to work quickly enough. When logging in externally however, this process takes around 20 seconds, and thus doesn't display the students' points values until you've clicked/searched a few times.
I'm using the following code in my PHP to access these transactions:
function getTotalPoints() {
$sql = "SELECT *
FROM `transactions`";
$res = mysql_query($sql);
$rows = array();
while($r = mysql_fetch_assoc($res)) {
$rows[] = $r;
}
if ($rows) {
return $rows;
} else {
$err = Array("err_id" => 1);
return $err;
}
}
So, my question is, how should I actually be approaching this? Full-text indices; maybe a student table with their total points values which gets updated every time a transaction is entered; mass-transactions (i.e. more than one student receiving the same points for the same category) grouped into a single database row? These are all things I've contemplated but I'd love someone with more DB knowledge than myself to provide enlightenment.
Example records
Table structure
Table overview
Assign Points interface
Many thanks in advance.
Your problem is your query:
SELECT * FROM `transactions`
As your data set gets bigger, this will take longer to load and require more memory to store it. Rather determine what data you need specifically. If it's for a particular user:
SELECT SUM(points) FROM `transactions` WHERE Recipient_ID=[x]
Or if you want all the sums for all your students:
SELECT Recipient_ID, SUM(points) AS Total_Points FROM `transactions` GROUP BY Recipient_ID;
To speed up selections on a particular field you can add an index for that field. This will speed up the selections, especially as the table grows.
ALTER TABLE `transactions` ADD INDEX Recipient_ID (Recipient_ID);
Or if you want to display a paginated list of all the entries in transactions:
SELECT * FROM `transactions` LIMIT [page*num_records_per_page],[num_records_per_page];
e.g.: SELECT * FROM `transactions` LIMIT 0,25 ORDER BY Datetime; # First 25 records
Adding to Tom's suggestion, you may want to consider normalizing your database further. I assume you now have 3 tables:
students (id, name, ...)
staff (id, name, ...)
transactions (id, student_id, staff_id, points, date, reason)
A more normalized form uses more tables with less data:
students (id, name, ...)
staff (id, name, ...)
transactions (id, staff_id, points, date, reason)
transactions_students (transaction_id, student_id)
Adding a transaction then becomes a two-step process: First you create one transaction record, and then you insert multiple records into transactions_students, each one linking the transaction to one student. Note that you can create a view that behaves exactly like the original denormalized table for selecting, something like:
CREATE VIEW vw_transactions AS SELECT transactions.*, transactions_students.student_id FROM transactions INNER JOIN transactions_students WHERE transactions_students.transaction_id = transactions.id
This will drastically reduce the number of records in the transactions table, and it avoids storing the date and the reason redunantly. The downside is that linking transactions to students requires one extra join - but if you have your foreign keys and indexes set up properly, this doesn't have to be a problem at all.
I'd index the Recipient_ID so you can search for 1 person specifically at any given point or at least be able to GROUP your data more effectively. If you do opt to group by category_id then i'd add a seperate or combined index to category_id too.
The second suggestion would be to GROUP and AGGREGATE your data on the fly. For example:
SELECT Recipient_ID, Category_ID, SUM(points) FROM transactions GROUP BY Recipient_ID, Category_ID
These two suggestions should dramatically upgrade your performance because instead of calculating the total points for your students on the PHP/JS side, you will do it directly on the database.