populate static values for missing database values - sql-server-2008

I have a query to pull some records from a database - using a few tables to tie agent names to their sales. My problem is - the agent phone_id and agent first_name and last_name isn't always in the database. For those values I'd like to populate "unknown" for their first and last name. My query as it exists today - just skips them as they don't match.
select recordings.ident,users.first_name,users.last_name,recordings.agent_number,recordings.device_id from recordings
join agent_phones
on recordings.agent_number=agent_phones.phone_id
join users
on agent_phones.agent_id=users.uid
is there a way to do some sort of "if" in the query? so that "if" the agent_number doesn't exist in agent_phones - i can just populate the first_name and last_name with the static "unknown".

You are looking for LEFT JOIN clause, which also includes rows that cannot be joined (don't have matching row in the second/right table). The values from the second/right table are then NULL.
SELECT recordings.ident, users.first_name, users.last_name, recordings.agent_number, recordings.device_id
FROM recordings
LEFT JOIN agent_phones
ON recordings.agent_number = agent_phones.phone_id
LEFT JOIN users
ON agent_phones.agent_id = users.uid
This can further be extended to return a specified string instead of NULL values using the COALESCE function:
SELECT
recordings.ident,
COALESCE(users.first_name, 'unknown'),
COALESCE(users.last_name, 'unknown'),
recordings.agent_number,
recordings.device_id
FROM ...

Related

MySQL Join statement to get data from two tables into a datagridview

I have two tables that I'm trying to join, 'holidays' and 'users'.
Users contains all my user info, the the column 'id' being primary and unique.
Holidays contains a column called 'userid', which corresponds to the id in the user table.
I'm struggling to get the join statement to work... what I'm looking for is the result of the select statement to give me the friendlyname (column 'fname' in user table) instead of giving me the value of userid.
Here's what I'm trying...
SELECT * FROM holidays JOIN users on users.id=holidays.userid WHERE holidays.status = 0
But i'm not getting a correct result - SQL executes without error, but my DGV is filled with tons of erroneous results.
Apologies If I have not used the correct terminology or whatever.
I'm new to the concept of joins.
Here is hopefully a better explanation of what I am after...
Thanks in advance.
You need to select the specific values you want from every table in the JOIN:
SELECT u.fname
FROM holidays h
JOIN users u
ON u.id = h.userid
WHERE h.status = 0
by the alias (FROM users u) you can select column from users table by u.fname
First try to right join to the User table. If you just want the fname then select the column name in the SELECT query, as SELECT * takes more time then SELECT column name.

A bit of trouble with mySQL querying

say I have a table called "users", which houses all the users of a system. Each user has a "role" as defined by the "roles" column in addition to a "name" and "id" column. Each user with the role "worker" is advised by a "supervisor" as defined by the "advised_by" column.
I'd like to query my database so that it returns the both the name of the worker and their supervisor and one line, is that possible without joins?
Thanks for any advise, I've been banging my head against this for a while now
Edit: Thanks to everybody who tried to help. Sorry, I guess that was a pretty vague/awful description in retrospect. I'll try to model the table better here.
Columns: Name, ID, Role, Advised_by
Row 1: Bob, 123, Worker, 321
Row 2: Tom, 321, Supervisor, N/A
I would like to return a result with all the people tagged as "Workers", along with their name and the name of their supervisor, so something like: Bob, Worker, Tom on one line.
I was trying to avoid adding a join because my professor asked us not to use them due to the performance hit, but it doesn't seem like there's a practical way around it, in which case I'll be alright with a join.
Edit 2: Guess I'm just an idiot, I realized after I typed it all out I could just do it pretty easily with aliasing. Sorry for the trouble guys
Some more details would be necessary, but you need to join the table to get both the name of the supervisor and worker in one MySQL sentence.
Assuming the advised_by column contains the ID of the user who advises this worker:
SELECT u.id, u.name, u2.id AS supervisorID, u2.name AS supervisorNAME
FROM users u, users u2
WHERE u.advised_by = u2.id AND u.role = 'worker'
At the risk of repeating the answer provided by EpochGalaxy...
Q: Is that possible without joins?
A: Yes. It is possible. One approach is to use a correlated subquery.
Consider the query you need to run to get the supervisor name...
SELECT s.name
FROM users s
WHERE s.id = 321
What if you ran a query like that for each row you retrieved from users.
Say you ran query like this:
SELECT u.id
, u.name
, u.role
, u.advised_by
FROM users u
ORDER BY u.id
And for each row from that query, right before you returned it, you ran a query to get the name of the supervisor.
We can achieve that by using a subquery in the SELECT list.
As a trivial example of running a subquery in the SELECT list consider this query. (There's no logical reason we'd run a query like this, but as a simple demonstration that we can run a subquery...
SELECT u.id
, u.name
, u.role
, u.advised_by
, ( SELECT 'bar' ) AS foo
FROM users u
ORDER BY u.id
The rows returned by this query will include an additional column, named foo. The value assigned to the column will be provided from the result of the subquery... "SELECT 'bar'".
Now that we know we can run a subquery in the SELECT list, and return a column with that, we can try something else. Like this:
SELECT u.id
, u.name
, u.role
, u.advised_by
, ( SELECT s.name
FROM users s
WHERE s.id = 321
) AS s_name
FROM users u
ORDER BY u.id
With that, for each row returned by the outer query, MySQL will run the subquery in the SELECT list, and take the value returned by the subquery, and put the value returned into a column of the row being returned by the outer query.
That subquery is going to get only the name from the row in users with id = 321.
So that doesn't really get us what we need.
Here's the trick... instead of a literal value 321, we can put there an expression that includes a reference to the table in the outer query.
SELECT u.id
, u.name
, u.role
, u.advised_by
, ( SELECT s.name
FROM users s
WHERE s.id = u.advised_by
) AS s_name
FROM users u
ORDER BY u.id
Aha!
Now, for each row returned by the outer query, MySQL will run the subquery in the SELECT this.
This time, the subquery includes a reference to the advised_by column from the row of the outer query. MySQL will take the value that's in the advised_by column from the row being returned (by the outer query), and then slide that into the subquery before the subquery executes. The return from the subquery goes into the column of the resulset.
With this, the results we get from the sbuquery are determined by values in the outer query. The subquery is related to the outer query.
Some important restrictions to notes: The subquery in a SELECT list of another query must return exactly one column. (It can be an expression, a literal. But the return from the subquery is not allowed to return two or more columns.
The subquery must return no more than one row. If it returns zero rows, a NULL value is assigned to the column in the outer query.
The subquery in the example above satisfies the conditions. There's exactly one expression in the SELECT list, and the id column is unique in the users table, so it can't return more than one row.
The SQL terminology for using a subquery like this is correlated subquery.
So, to answer your question, yes... it is possible to achieve the specified result without a join operation.
Some other notes:
In terms of performance, it's important that the subquery be efficient. It is going to be executed for every row returned by the outer query. If we're returning 10,000 rows, that's 10,000 executions of the subquery.
So, this approach is best suited to cases where the outer query is returning a small number of rows, and the correlated subquery is very efficient.
Use the following query:
SELECT (u.name)workername, (select name from users where id=u.advised_by)supervisor FROM `users` u where u.roles="worker"
Sample table structure as described by you:
--
-- Database: `test`
--
-- --------------------------------------------------------
--
-- Table structure for table `users`
--
CREATE TABLE `users` (
`id` int(11) NOT NULL,
`name` varchar(255) NOT NULL,
`roles` varchar(255) NOT NULL,
`advised_by` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
--
-- Dumping data for table `users`
--
INSERT INTO `users` (`id`, `name`, `roles`, `advised_by`) VALUES
(1, 'test1', 'supervisor', 0),
(2, 'test2', 'worker', 1),
(3, 'test3', 'worker', 1);

Trouble with LIKE CONCAT in mysql query

I have two tables: users and tabletop_questions. The users table has a column called institution_primary_function and tabletop_questions has a column called target_institutions. An example value for users.institution_primary_function = C and an example value for tabletop_questions.target_institutions = A,B,C,D,E,F.
I am trying to return only those rows where the value for users.institution_primary_function is contained in tabletop_questions.target_institutions (comma delimited list) using the below query.
SELECT * FROM tabletop_questions
LEFT JOIN users
ON users.institution_primary_function
LIKE CONCAT( '%,', tabletop_questions.target_institutions, ',%' )
However, with this query, every row from the tabletop_questions table is returned with all the values from the joined users table as NULL. Could you please advise me as to where I am going wrong?
You should normalize your data because searching through a comma-delimited string is not efficient. Yet, MySQL includes a function for this called FIND_IN_SET(). Use an INNER JOIN instead of a LEFT OUTER JOIN to only return matching records.
SELECT * FROM tabletop_questions
INNER JOIN users
ON FIND_IN_SET(users.institution_primary_function,
tabletop_questions.target_institutions)

Use count of unrelated table in SQL query

I have this query:
select skill.name, IFNULL(Round(((SUM(ROUND((student_skills.value/skill.value)*100,0)))/82),0),0) as successRate from skill left JOIN student_skills on skill.id = student_skills.skill_id group by skill.name
This query returns exactly what I want but I need to replace constant 82 (just for example) with number of rows in table user (something like COUNT(user.name)).
Problem is that user is not related to skill or student_skill table in any way.
How should I alter my query so that it would use current count of users?
Thanks
Use a subquery
select skill.name,
IFNULL(Round(((SUM(ROUND((student_skills.value/skill.value)*100,0)))/(select COUNT(*) from user)),0),0) as successRate
from skill
left JOIN student_skills on skill.id = student_skills.skill_id
group by skill.name

Complex SQL query

I have need to write a query which is a little complicated for me to put together. The basic idea is to match a couple of fields from different tables and then edit another table based on the result.
There are three tables involved:
Schedules: sch_id, date, schedule, event_id
Link_Location_Schedules: id, loc_id, sch_id
Link_Location_Events: id, loc_id, event_id
Now what I need to try and do is:
find schedules that are set after todays date in "Schedules".
for these schedules get location ids from Link_Location_Events where event_ids equal the schedule event id.
for each of the matched schedules (sch_id) and returned locations (loc_id) check if the pair already exist in the Link_Location_Schedules, if not insert them.
Here are some SQL queries I have done for the above, I just need to combine them some how:
SELECT sch_id FROM 'Schedules' WHERE DATE_FORMAT(sports_schedule_insert_date_time, "%Y-%m-%d") >= '2012-11-14';
SELECT loc_id from Link_Location_Events, Schedules WHERE Link_Location_Events.event_id = Schedules.event_id;
sounds like a simple insert from select statement...
insert into Link_Location_Schedules
( loc_id,
sch_id )
select
PreQuery.loc_id,
PreQuery.sch_id
from
( select
s.sch_id,
lle.loc_id
from
Schedules s
join Link_Location_Events lle
on s.event_id = lle.event_id ) PreQuery
LEFT JOIN Link_Location_Schedules lls
on PreQuery.loc_id = lls.loc_id
and PreQuery.sch_id = lls.sch_id
where
lls.loc_id is null
The innermost prequery is to get all possible schedule / location IDs. From that, left-join to the existing location/schedules on those found. Then, the WHERE clause will return only those where NO MATCH WAS FOUND (thus the lls.loc_id is null). Take that result and insert directly into the schedule / location table.