Query to see how many times employees has worked same shifts - php

I run a management system where people who work different shifts are registered.
I'd like to be able to make a display of how many times each worker/volunteer worked same shifts, like this:
|Amy|Carl|Max|
|---|----|---|
Amy | X | 2 | 6 |
Carl| 2 | X | 5 |
Max | 6 | 5 | X |
I was hoping you had some ideas how to form the query.
The only idea I've come up with so far is to make PHP create a custom query for each user.
Select count(common between user 1 and 2), count(common between user 1 and ...)
Select count(common between user 2 and 1), count(common between user 2 and ...)
etc..
I consider this an ugly way to do it and I am hoping there is some way of retrieving this data within a single query.
The database is stored like this:
Shifts
ID
From
To
Working
ID
ShiftID
UserID
Users
ID
Name

You'll have to self-join the Working table:
SELECT a.UserID, b.UserID, count(a.ShiftID) AS common_shifts
FROM Working AS a
INNER JOIN Working AS b ON ((a.ShiftID = b.ShiftID) AND (a.UserID <> b.UserID))
HAVING common_shifts > 0

Couldn't you do a cross join where each row is compared to the other, and handle the case of userid=userid to put an X instead?

Related

Display Current Friends

I am developing a Friend Request system and currently stuck at one point. I have two tables i.e. member and requests. requests table stores user_id and friend_id of two users and I want to display names of current friends that are to be fetched from member table. For example, request table:
request_id | user_id(to) | friend_id(from) | status
2 | 2 | 3 | 1
3 | 3 | 1 | 1
6 | 4 | 2 | 1
7 | 2 | 1 | 1
I have achieved the current partners with the query below;
SELECT * FROM requests WHERE user_id='2' OR x.friend_id='2' AND x.status='1'
but all I can display for now are id's. What I am trying to achieve is getting the correct names according to the id's as well which are stored in the member table. Data stored in member table is;
member_id | name
1 | John
2 | Steve
3 | Sarah
4 | Stuart
So, if id no. 2 & 3 are friends, the name of the added friend should be displayed in user's profile who accepted the request.
What I am trying to do:
SELECT
x.*,
y.*
FROM
requests x,
member y
WHERE
x.user_id='$member_id' OR
x.friend_id='$member_id' AND
y.member_id = '$member_id' AND
x.status='1'
The result of this query gets a list of other members as well regardless of the member_id I'd specify. Can anybody please point out what I am doing wrong here?
This should return the list you are looking for:
SELECT *
FROM requests x
JOIN member y
ON x.user_id = y.`member_id` OR x.friend_id = y.`member_id`
WHERE x.status = '1' AND y.member_id = '$member_id'
It works by using an inner join on the two tables, getting all of the rows that match the user_id or member_id, and then limiting the list to the is in $member_id.
Although you do not include any other code in your question, I suspect you are using PHP and mysqli to run this query. I would suggest using prepared queries instead of simple variable substitution so you can avoid SQL Injection.
SELECT name from member where user_id IN (select friend_id from request where user_id='$member_id' AND status=1);
Hope this will works!

LIMIT result on join MySQL

take the case you have 2 table, for example tbCostumers and tbOrders.
I would like to display a summary list with all costumers, related orders and display them with a paginator.
Doing a join I can extract costumers list and all orders for each costumer, the result is something like:
idCostumer | name | ... | idProduct | productName | price | ...
Where the first n columns are all equal if the costumer has more than 1 order. So I can have:
1 | will | ... | 12 | product1 | 123 | ...
2 | bill | ... | 23 | product2 | 321 | ...
2 | bill | ... | 24 | product3 | 231 | ...
And so on
I'm trying to use LIMIT to extract only n records and using them with a paginator.
First question: if a costumer has more than 1 order, with this query I'll see n records, equal in the first column (id, name, ... and other costumer info) but different at the end, where there are products info. Is this 'correct'? Is there another way to extract this informations?
Second question: if I do that and I use a LIMIT, I could "cut" the result table between 2 (or more) records that represent the same customer; so, for example in the small table above, if I limit with 2 the third row will be lost, even if it's part of the row above, because is just another order of the same costumer.
I would like to limit the number of different idCostumer, in order to take exactly n costumers, even if they appear more than 1 times in the result table. Something like n different idCostumer, no matter if they are repeated.
Is this possible?
I hope it's clear, it was not easy to explain what I would like to achieve :)
Thank you!
You might want to have something like this:
SELECT * FROM (
(SELECT * FROM tbCustomers LIMIT 3) AS c
INNER JOIN tbOrders AS o ON o.customer = c.idcustomer
);
You can substitute the first asterisk with named columns and only receive your desired columns in the order you prefer (ie: SELECT c.name, o.price FROM...) .
Hope this works for you!
EDIT: changing the value of the LIMIT clause changes the number of the picked customers, of course.
EDIT 2: As Alvaro Pointed out, you'll probably need an order clause in the tbCustomers query.

Most efficient JOIN query - MySQL

Below is a gross over simplification of 2 very large tables I'm working worth.
campaign table
| id | uid | name | contact | pin | icon |
| 1 | 7 | bob | ted | y6w | yuy |
| 2 | 7 | ned | joe | y6e | ygy |
| 3 | 6 | sam | jon | y6t | ouy |
records table
| id | uid | cid | fname | lname | address | city | phone |
| 1 | 7 | 1 | lars | jack | 13 main | lkjh | 55555 |
| 2 | 7 | 1 | rars | jock | 10 maun | oyjh | 55595 |
| 2 | 7 | 1 | ssrs | frck | 10 eaun | oyrh | 88595 |
The page loops thru the records table and prints the results to an HTML table. The existing code, for some reason, does a separate query for each record "select name from campaign where id = $res['cid']" I'd like to get rid of the second query and do a some kind of join but what is the most effective way to do it?
I need to
SELECT * FROM records
and also
SELECT name FROM campaigns WHERE campaigns.id = records.cid
in a single query.
How can I do this efficiently?
Simply join the two tables. You already have the required WHERE condition. Select all columns from one but only one column from the other. Like this:
SELECT records.*, campaigns.name
FROM records, campaigns
WHERE campaigns.id = records.cid
Note that a record row without matching campaign will get lost. To avoid that, rephrase your query like this:
SELECT records.*, campaigns.name
FROM records LEFT JOIN campaigns
ON campaigns.id = records.cid
Now you'll get NULL names instead of missing rows.
The "most efficient" part is where the answer becomes very tricky. Generally a great way to do this would be to simply write a query with a join on the two tables and happily skip away singing songs about kittens. However, it really depends on a lot more factors. how big are the tables, are they indexed nicely on the right columns for the query? When the query runs, how many records are generated? Are the results being ordered in the query?
This is where is starts being a little bit of an art over science. Have a look at the explain plan, understand what is happening, look for ways to make it more efficient or simpler. Sometimes running two subqueries in the from clause that will generate only a subset of data each is much more efficient than trying to join the entire tables and select data you need from there.
To answer this question in more detail, while hoping to be accurate for your particular case will need a LOT more information.
If I was to guess at some of these things in your database, I would suggest the following using a simple join if your tables are less than a few million rows and your database performance is decent. If you are re-running the EXACT query multiple times, even a slow query can be cached by MySQL VERY nicely, so look at that as well. I have an application running on a terribly specc'ed machine, where I wrote a cron job that simply runs a few queries with new data that is loaded overnight and all my users think the queries are instant as I make sure that they are cached. Sometimes it is the little tricks that really pay off.
Lastly, if you are actually just starting out with SQL or aren't as familiar as you think you might eventually get - you might want to read this Q&A that I wrote which covers off a lot of basic to intermediate topcs on queries, such as joins, subqueries, aggregate queries and basically a lot more stuff that is worth knowing.
You can use this query
SELECT records.*, campaigns.name
FROM records, campaigns
WHERE campaigns.id = records.cid
But, it's much better to use INNER JOIN (the new ANSI standard, ANSI-92) because it's more readable and you can easily replace INNER with LEFT or other types of join.
SELECT records.*, campaigns.name
FROM records INNER JOIN campaigns
ON campaigns.id = records.cid
More explanation here:
SQL Inner Join. ON condition vs WHERE clause
INNER JOIN ON vs WHERE clause
SELECT *
FROM records
LEFT JOIN campaigns
on records.cid = campaigns.id;
Using a left join instead of inner join guarantees that you will still list every records entry.

Filter MySQL records between two tables by Join depending on a specific column value

Recently I've been working on a PHP/MySQL script which reads information from a database with user info and file info stored in two separate tables.
Below are the schema's for the tables.
Table1
UID | Username | PermissionLevel
1 | First | 1
2 | Next | 3
3 | More | 2
Table2
FID | Filename | FileLevel | UploadUsername
1 | file.txt | 2 | First
2 | hand.mp4 | 1 | First
3 | 1245.dds | 1 | Next
4 | beta.sql | 3 | More
For the purpose of this message I have omitted the passwords column and the file title/description column, since they play no part in the result I am trying to achieve.
So far I have come up with this SQL code
SELECT DISTINCT table2.*,
table1.*
FROM table2 JOIN table2 ON table2.FileLevel <= table1.PermissionLevel
WHERE table2.UploadUsername = table1.Username
ORDER BY FID DESC LIMIT 7
This generates the appropriate listing I want, but does not filter the level of content shown.
Any user with a PermissionLevel of 1 should only see Files with a FileLevel of 1. Users with PermissionLevel of "2" can see files of FileLevel of both 2 AND 1, and so on.
But at the current stage it seems to just want to display ALL results regardless of File/Permission Level.
I've been stuck at this issue for a couple of days now and just can't seem to get my head around this.
It's likely to be something simple I may have overlooked, but I hope that a fresh pair of eyes may help me.
I'm not sure if I understand the question fully, but this is what I could make of it. You have a query that returns all uploaded files. You now want to filter that list, so it sometimes shows less results, depending on the user's permission level. Please note that this user is the active user on the website, who is not necessarily the same user who uploaded a file, so this condition does not work on the table1 table of your query.
A common solution to this is to have a session variable storing your current user's id, and possibly other information.
$_SESSION['user'] = 'somebody';
$_SESSION['permissionLevel'] = 3;
If you don't have permissionLevel in a local variable, you will have to join on the table1 table twice, once to find the uploader and once to find the permission level of the current user. You also have a typo in your original query. The following will give you both users
SELECT *
FROM table2
JOIN table1 uploader WHERE table2.UploadUsername=table1.Username
JOIN table1 currentuser WHERE table2.PersmissionLevel<=table1.PermissionsLevel AND users.Username='$_SESSION[user]'
ORDER BY FID DESC

mySQL JOIN query beat down

Alright, I'm not the best with JOIN's and after all these years of working with mySQL you think I would be by now at the least minimally decent. Guess I've never really worked on anything superbly complex til now worth needing to join a table. So here I am, confused ever so slightly in need of a helpful example to get me on a roll, something that's pertinent to my actual data that I can make heads or tales of cause all the reading I'm doing online else where just gives me headaches for the moment. I think I might be stuck on the mythology of JOIN's being a hard thing to do, they don't seem like it but when ever I've tried I fail. So anyway I am working with PHP as my server side coding, and I believe MySQL 5.
So heres the construct to an extent.
I have table information and table connections.
Connections has: member_id, connection_id, active
Information has: firstname, lastname, gender, member_id
I should say the tables contain more data per table, but as I understand it I need write a query that I can use the member_id as the connector/foreign key. Where I can use both sides of the information. I need to know if active is 1, and then I need to know all of the columns above mentioned for information.
I tried
SELECT member_id,
connection_id,
active,
firstname,
lastname,
gender,
member_id
FROM connections, information
WHERE connection.member_id = information.member_id AND
connection.active = 1
and I've tried
SELECT * FROM connections, information
WHERE connection.member_id = information.member_id AND
connection.active = 1
With the first one I get member_id is ambitious which is understandable to a point i think cause of the matching columns between the two tables. Then the second query doesn't server me well as it only results with one person.
My Ultimate goal is to find all the connections for a specific member_id in the connections table, while gathering all the information about those connections from the information table using the connection_id as its the same thing as the member_id in the in the information table.
So in laymans terms if I am not making sense lets say I wanted to list out all my friends in from the DB. My connection table lets me know which people I am connected to where member_id is my id and connection_id is my friends member_id on another table. Hopefully that makes more sense. And this is where I am having trouble with my query and trying to write it correctly. If I could get a working sane sample of that I think I might be able to make better sense of JOIN's doesnt help that I also can't figure out what type of JOIN is best suited for my needs either I suppose.
EDIT....
Ok as per request from comment below. Sample data expected output from tables that look similar to this:
Connections Table
member_id, connection_id, active
1 | 2 | 1
1 | 3 | 1
1 | 4 | 1
1 | 5 | 1
2 | 1 | 1
2 | 5 | 1
3 | 1 | 1
Information Table
member_id, firstname, lastname, gender, ...other unimportant rows for this query
1 | Chris | Something | m | ....
2 | Tony | Something | m | ....
3 | Brandon | Something | m | ....
4 | Cassie | Something | f | ....
5 | Jeff | Something | m | ....
6 | John | Something | m | ....
now from the connections table I need to gather all the connection_id's associated with my member_id where active is 1 then from the information table gather everyone firstname, lastname, gender.. Now I know I can do this 2 step where I pool all the connection_id's from connections then run them through a loop of some sort and one by one get the resulting id's from the first query but to me that seems a bit obscure and process intensive which I want to avoid, which brings me here.. Currently from my original query posted to the many shared thus far trying to help my results are to the effect of
1 | Chris | Something | m | 2
1 | Chris | Something | m | 3
1 | Chris | Something | m | 4
1 | Chris | Something | m | 5
what I'd like to see returned is something like
2 | Tony | Something | m
3 | Brandon | Something | m
4 | Cassie | Something | f
5 | Jeff | Something | m
After looking at this I suppose I would also need to know the friendID column that matches my member_id as well but thats something to figure out after this initial hurdle
The error is in your WHERE Clause because instead of Connections you wrote it Connection which then the server generates the error.
...
WHERE connection.member_id = information.member_id AND
connection.active = 1
try this:
SELECT a.Member_ID,
a.FirstName,
a.LastName, a.gender,
b.Connection_ID
FROM Information a INNER JOIN Connections b
on a.Member_ID = b.Member_ID
WHERE b.`Active` = 1
UPDATE
if that's the case then you will most likely have a SELF JOIN
SELECT DISTINCT b.Connection_ID,
c.*
FROM Information a INNER JOIN Connections b ON
a.Member_ID = b.Member_ID
INNER JOIN Information c ON
b.Connection_ID = c.Member_ID
WHERE b.`Active` = 1
AND a.Member_ID = 'ID HERE' -- If you want to get for specific member
The error in the first is "ambiguous" not ambitious. Ambiguous means that the SQL engine doesn't know which column you are talking about, because you have two columns with the same name (different tables but still).
You can fix that by specifying the table name along with the column name where you list the columns for select.
For example
SELECT connections.member_id, connection_id, active, firstname, lastname, gender, information.member_id FROM connections, information WHERE connections.member_id = information.member_id AND connections.active = 1
The problem with returning only one suggests that there is only one record that matches your query but it's hard to guess.
Try changing to:
SELECT * FROM connections c JOIN information i ON i.member_id = c.member_id WHERE c.active = 1
Try this:
SELECT *
FROM information
LEFT OUTER JOIN connections
ON information.member_id = connections.member_id
WHERE connections.active = 1;
You're joining on the wrong tables. You said:
where member_id is my id and connection_id is my friends member_id on another table
Then, what you have to match is connections.connection_id with information.member_id. The simplest solution is:
select c.member_id, c.connection_id, c.active from connections c
join information i on c.connection_id = i.member_id
where c.active = 1 and c.member_id = #yourId
That's all :)

Categories