Mysql knowledge is far from perfect. I cannot get it all togheter so I thought I might give it a try here to understand the logic.
I've got two tables
Table: office
ID (int (pk))
name (varchar)
and
Table: staff
ID (int (pk))
office_id (int not null)
chief_id (int)
name (varchar)
wage (float)
I want to :
a) Select all people, who get paid more than their direct chiefs
b) Select a list of all offices along with a person with the highest wage in each. if more than one person has the highest wage, display them all. The office should be selected even if it has no people.
c) Select all chiefs, who have exactly one direct subordinate.
d) Select all offices sorted by total wage of people in it, descending.
Any idea where I should start ?
Thanks in advance!
Start from a)
SELECT s.*, chief.wage AS chief_wage
FROM staff s, staff chief
WHERE s.chief_id = chief.id
AND s.wage > chief.wage
Here we use self join to add the chief's data to all the staff. And then just compare salaries.
Related
I have a schema design question for my application, hope I can get advices from teachers. This is very alike of Role Based Access Controll, but a bit different in detail.
Spec:
For one company, there are 4 roles: Company (Boss) / Department (Manager) / Team (Leader) / Member (Sales), and there are about 1 million Customers records. Each customer record can be owned by someone, and he could be Boss or Manager or Leader or Sales. If the record's owner is some Sales, then his upper grade (say: his leader / manager / boss) can see this record as well (but others: say the same level of his workmates, cannot see, unless his upper grade manager share the customer to his workmates), but if the record's owner is boss, none except the boss himself can see it.
My Design is like this (I want to improve it to make it more simple and clear):
Table:
departments:
id (P.K. deparment id)
d_name (department name)
p_id (parent department id)
employees
id (P.K. employee id)
e_name (employee name)
employee_roles
id (P.K.)
e_id (employee id)
d_id (department id)
customers
id (P.K. customer id)
c_name (customer name)
c_phone (customer phone)
permissions
id (P.K.)
c_id (customer id)
e_id (owner employee id)
d_id (this customer belongs to which deparment)
share_to (this customer share to other's id)
P.S.: each employee can have multi roles, for example, employee A can be the manager of department_I and meanwhile he can also be one sales of deparment_II >> Team_X.
So, when an employee login to application, by querying from employee_roles table, we can get all of the department ids and sub department ids, and save them into an array.
Then I can use this array to query from permissions table and join it with customers table to get all the customers this employee should see. The SQL might look like this:
SELECT * FROM customers AS a INNER JOIN permissions AS b ON a.id =
b.c_id AND (b.d_id IN ${DEP_ARRAY} OR e_id = ${LOGIN_EMPLOYEE_ID} OR
share_to = ${LOGIN_EMPLOYEE_ID})
I don't really like the above SQL, especially the "IN" clause, since I am afraid it will slow down the query, since there are about 1 million records or even more in the customer table; and, there will be as many records as the customers table in the permissions table, the INNER JOIN might be very slow too. (So what I care about is the performance like everyone :))
To my best knowledge, this is the best design I can work out, could you teachers please help to give me some advice on this question? If you need anything more info, please let me know.
Any advice would be appreciated!
Thanks a million in advance!!
Do not use an array, use a table, ie the value of a select statement. And stop worrying about performance until you know more basics about thinking in terms of tables and queries.
The point of the relational model is that if you structure your data as tables then you can looplessly describe the output table and the DBMS figures out how to calculate it. See this. Do not think about "joining"; think about describing the result. Whatever the DBMS ends up doing is its business not yours. Only after you become knowledgeable about variations in descriptions and options for descriptions will you have basic knowledge to learn about performance.
I have a table Books with isbn and name of books, and I have a table orders with oisbn(foreign key) and ocid (foreign key, customer ID of he who has bought the book).
A
I want to list the cids of those customers who have ordered only ocid=123 or ocid = 567,NOT both. Kind of like XOR.
How do I accomplish this in mysql? I've been thinking for a long time and I can't figure it out.
SELECT
foo
FROM
bar
WHERE ocid IN (123, 567)
GROUP BY customerId
HAVING COUNT(*) = 1
I have a MySQL table with around 4 million+ rows. Let us say the table is as follows:
Columns in table Person:
Id
Name
Age
Marital Status
Education Level
'Location Country'
'Description'
When I run a query based on Age, I also want to have a summary count of people with the same age in different marital status and also with different 'Education Level' and 'Location Country'.
When I run a query based on Age and Education Level, I also want to have a summary count of people with the same age and Education Level in different marital status and also with different 'Location Country'.
For example, the query issued would be SELECT * FROM Person WHERE Age = 27;. I also want results that would be produced by SELECT Education Level, COUNT(*) FROM Person WHERE Age = 27 GROUP BY Education Level; and SELECT Location Country, COUNT(*) FROM Person WHERE Age = 27 GROUP BY Location Country;
Also, this becomes more challenging for me when I have to do a search based on keywords on description and want a summary count on each of the other columns. The application I am developing is a sort of search engine. This can be seen in sites like Ebay,
I can possibly run these queries separately. But, with 4 million rows, the GROUP BY query will take substantial amount of time. This is an internet application and the query should complete within few seconds.
Any help would be much appreciated.
You can do both in one query
SELECT p.*, count(p2.id)
FROM Person p, Person p2
WHERE p2.Age = p.age and p2.marital != p.marital and p1.education != p2.education
GROUP BY p1.id
In such situation, I would suggest to save data in a memcache cache. You can expire cache if new data inserted to table or after some expiration time, to avoid long query execution. Another improvement would be using a LIMIT to reduce number of row returned by DB like this:
SELECT p.*, count(p2.id)
FROM Person p, Person p2
WHERE p2.Age = p.age and p2.marital != p.marital and p1.education != p2.education
GROUP BY p1.id
LIMIT 10
From what you are describing, I would have a separate aggregate table to query directly from that has those "roll-up" stats you want. How frequent is the "Person" table getting added to / changed. If you are only storing a person's "Age", what is the basis of the age if no date, and you add the person again in future they would have multiple records... such that
At age X, so many people were married (or not) and had this level of education.
At age Y, so many people... etc..
I would create a summary table, something like
create table AgeStat (
age int,
married int,
single int,
divorced int,
HighSchool int,
Associates int,
Bachelors int,
Masters int,
Doctorate int )
Then, add a trigger to the person table such that during insert (or inclusive of update/delete as needed), the new record just adds 1 to each respective count applicable.
Then, for your web app, it would be instantaneous to grab one record from this summary table where age = 27 and you have ALL your classification stats.
However, if you distinctly wanted to know how many Married with Masters degree, you would have to roll back to master person list.
Alternatively, you could do a similar pre-aggregation but down a level of granularity something like
create table AgeStat (
age int,
maritalstat int, -- but I would actually use an enumerated value for marital status
educationlevel int, -- and education level vs a hard description of each.
peoplecount int )
and likewise have a trigger that updates the count based on the two combination elements per age. Then, if you wanted the total "Married", you can sum(peoplecount) for age = 27 and maritalstat=(enumerator for "married" value)
Good luck, and hope it helps alternative solution for you.
I have a Query that looks up an Employee ID, Employee Name and Team Name from the current Staff Database. I have another Query that lists all unique values in Team Name. (Team Name is an Integer, and corresponds to Employee ID, also an Integer.)
Eg this is how teams are structured. Emp ID 100 belongs to Emp ID 10's team. 10 belongs to 5. 5 belongs to 1, etc.
EmpID = 100
TeamName = 10
EmpID = 10
TeamName = 5
EmpID = 5
TeamName = 1
What I am trying to do is return a fourth field, giving an asterisk, "*", when the Emp ID also appears in the Team Name query (Thus meaning they have a team/are a Manager).
I have a DCount that works, but it is slower than I'd like, and will only get slower as the Database grows, but it might serve to explain what I need.
Expr1: IIf(DCount("TeamName","jdbo_MostRecentEmpDataRemain","TeamName = " & [EmpID])>0,"*","")
jdbo_MostRecentEmpDataRemain is a Query that returns all data for staff that are active.
This will return an Asterisk if the EmpID has team members assigned to them, and nothing if they do not.
I'm wondering if this can be applied through queries to make it faster. Please let me know if you have any suggesstions.
I tried this: Expr2: IIf([EmpID] In ([qryListOfTeams].[TeamName]),"a","z")
but that returns lots of z's and then an a, as it seems to return a value for every value that is in the Team List. I want it to aggregate those and display an a if there is an a, otherwise a z. (Where in the original "*" is the a, and "" is the z)
Kind regards,
Jamie Warburton
How about:
SELECT * FROM TableOrQuery
LEFT JOIN (SELECT DISTINCT EmpID FROM Teams
WHERE EmpID In (SELECT TeamName FROM Teams)) As a
ON TableOrQuery.EmpID = a.EmpID
Derived tables are usually faster than subqueries.
EDIT re comment
Asterisk has a specific meaning, so while you can do this, I do not recommend it.
SELECT TableOrQuery.*, a.IsTeam FROM TableOrQuery
LEFT JOIN (SELECT DISTINCT EmpID, "*" As IsTeam FROM Teams
WHERE EmpID In (SELECT TeamName FROM Teams)) As a
ON TableOrQuery.EmpID = a.EmpID
Hi were trying to perform a mysql select which isnt going to plan and hoping someone can shed some light on it.
we have estimated 10,000 plus listing records, a customer can have several listing records for different locations. we need to select all customer listings where at least one of the locations is equal to a specifield location.
so for example lets say customer 1 has a listing in sheffiled, doncaster, leeds, wakefield and customer 2 has listings in london and brighton.
Now I want to select all customer listings where one of the listings is for the area sheffield.
Id hope to get back the 4 rows for customer 1 because one of his listings is in sheffield.
for the sake of this example lets just presume the table consists of just customerId and LocationName
I need to select all customerIds where one of the locationNames = sheffield. So Id get 4 rows retruend with the cusotmer ID and the 4 locations
How do you write this query in mysql? Im guessing subselect but not too sure.
SELECT customerid FROM customers_location
WHERE customerid IN(SELECT DISTINCT customerid FROM customers_location WHERE LocationName = 'sheffield')
Something like:
SELECT * FROM CUST_TABLE WHERE CUST_ID IN (
SELECT DISTINCT CUST_ID FROM CUST_TABLE WHERE CUST_LOCN='Sheffield')
Note; The distinct clause may not be strictly necessary, not sure.
That would give you eg. 4 records for customer xyz who has one of their listing locations as Sheffield, which I think is what you're asking.