I have 2 tables that looks like the below:
Table 1
Table 2
What Im trying to do, is I want to substitute the change_builder ID from table 1 by the first and last name from table 2. In addition, I want to do the same for the change_manager_ID in table 2 (Substitute it by the first and last name from table 2)
My query looks like the below:
SELECT a.change_number, a.title, change_manager_id,change_builder_id, concat(users.first_name,' ', users.last_name) as Manager_Name, concat(users.first_name,' ', users.last_name) as Builder_Name,
(CASE
WHEN a.change_state_id = '128' THEN 'In Progress'
WHEN a.change_state_id = '127' THEN 'Approved'
WHEN a.change_state_id = '125' THEN 'Pending'
WHEN a.change_state_id = '124' THEN 'Requested'
END) AS Change_State
FROM change_item as a
LEFT JOIN users
ON a.change_manager_id = users.id
WHERE a.change_state_id = 128
OR a.change_state_id = 124
OR a.change_state_id = 125
OR a.change_state_id = 127
The output of this is changing the first and last name of the manager w.r.t the ID but I want to do the same for the builder as well.
I'm stuck, any help or hint would be really appreciated.
Seems you have forgotten that you can join a table twice to the same other table - each join depicting a different relationship.
Good practice requires you to give each join clause a good correlation name to describe the role of the relationship.
And, please, use the right literals for the right types.
Not once change_state_id = '128' (string) and then change_state_id = 124 (number). Implicit conversions are slow and can impact the data quality.
And I used an IN () clause instead of a bunch of OR-s:
SELECT
a.change_number
,a.title
,change_manager_id
,change_builder_id
,CONCAT (mgr.first_name,' ',mgr.last_name) AS Manager_Name
,CONCAT (bld.first_name,' ',bld.last_name) AS Builder_Name
,CASE
WHEN a.change_state_id = 128 THEN 'In Progress'
WHEN a.change_state_id = 127 THEN 'Approved'
WHEN a.change_state_id = 125 THEN 'Pending'
WHEN a.change_state_id = 124 THEN 'Requested'
END AS Change_State
FROM change_item AS a
LEFT JOIN users AS mgr -- join as manager
ON a.change_manager_id = mgr.id
LEFT JOIN users AS bld -- join as builder
ON a.change_builder_id = bld.id
WHERE a.change_state_id IN(128,124,125,127)
;
Related
I have the following output:
Username
shortname
data
test1
firm
Google
test1
type
IT
test1
agreed
1
test2
firm
Facebook
test2
type
IT
test2
agreed
1
test2
newsletter
1
I want to make another column that makes the following: if username has the shortname "newsletter" and "newsletter" has the data "1" then "yes", if username does not have newsletter then "no"
So I want to have the following output:
Username
yes/no
test1
no
test2
yes
I made the following code:
SELECT distinct(if(shortname = 'newsletter' and data = 1, 'Yes', 'No')) as 'Yes/no', username
FROM prefix_user as u
JOIN prefix_user_info_data as uid ON uid.userid = u.id
JOIN prefix_user_info_field as uif ON uid.fieldid = uif.id
But this writes out yes or no in every single row
You can use conditional aggregation as
SELECT username,
MAX(CASE
WHEN shortname = 'newsletter' AND data = 1 THEN
'Yes'
ELSE
'No'
END) AS "yes/no"
FROM prefix_user as u
JOIN prefix_user_info_data as uid
ON uid.userid = u.id
JOIN prefix_user_info_field as uif
ON uid.fieldid = uif.id
GROUP BY username
considering the alphabetical order of the word Yes comes later than No
Is this on Oracle? Actually even if not you may take the idea on below query.
select case
when shortname = 'newsletter' and data = '1'
then 'YES'
else 'NO'
end as yes_no
from prefix_user as u
JOIN prefix_user_info_data as uid
ON uid.userid = u.id
JOIN prefix_user_info_field as uif
ON uid.fieldid = uif.id
From the tags you've added, I'm taking it as MySQL. In your IF condition, in the case where shortname='newsletter', you will have to add a nested IF condition to check if the data value is equal to 1.
The query will be something like following for checking for all the users will be selected instead of DISTINCT based on the IF conditon:
SELECT
IF( shortname = 'newsletter',
IF (
data= 1,
'yes',
'No')
, 'No') AS 'Yes/no',
username,shortname, data
FROM
test1 AS u //Relace your table name here
//add joins with other tables that you requires.
I have two tables, tasks and views, with the following structure:
tasks
-- id
-- status
views
-- id
-- taskid (FK of tasks.id)
-- status
And the tasks table, has a row with id = 1 and status = 1, whilst the views table has two rows with id = 1, taskid = 1, status = 1 and id = 2, taskid = 1, status = 0.
When I try to get all the tasks id that have all its views status set to 1 and the task's status itself set to 1 too and only, then I get in return a row with task id = 1 because view number 1 is set to 1 and view number 2 is set to 0.
So basically, what I need is an SQL statement that returns only one row for each task that has all its views and task status set to 1 (tasks.status = 1, views.status = 1) and only when that happens, and if any of the tasks' views is set to something different than 1, then the SQL statement doesn't return it.
Here is my SQL Statement so far which kind of works, but there is still something I am missing because it doesn't work as expected. Sorry if something isn't clear!
SELECT tasks.id FROM tasks JOIN views ON tasks.id = views.taskid WHERE tasks.status = 1 AND views.status = 1;
Join tasks to a query that uses aggregation to return only the taskids with min status set to 1 (which means there is no 0):
SELECT t.id
FROM tasks t
INNER JOIN (
SELECT taskid
FROM views
GROUP BY taskid
HAVING MIN(status) = 1
) v ON v.taskid = t.id
WHERE t.status = 1;
with t as (select taskid,
count(status) status_cnt,
sum(case when status = 1 then 1 else 0 end) as status_1_cnt
from views
group by taskid),
t2 as (select taskid from t where status_1_cnt > 0 and status_cnt = status_1_cnt)
select tasks.id from tasks join t2 on tasks.id = t2.taskid and status = 1
so If I am reading your question correctly you want all of the statuses in the view to be 1 per taskid. so I would count the view statuses and compare that count to where the view status is 1. (the case statement).
then just join this to the task table where the task status is 1
(although I like #forpas answer better)
Conceptually you only want to join on the records in the views table where status = 1, so like this:
SELECT A.id
FROM
tasks A
INNER JOIN
(
SELECT
tasks.taskid
FROM
views
WHERE
view.status = 1
) B
ON A.id = B.taskid
Although the syntax is less intuitive, this is equivalent and shorter:
SELECT
tasks.id
FROM
tasks
JOIN views
ON tasks.id = views.taskid
AND view.status = 1
WHERE
tasks.status = 1
This should also work, for a different reason (more like a trick):
SELECT A.id
FROM
tasks A
INNER JOIN views B
ON a.id = b.taskid
and a.status = b.status
WHERE
A.status = 1
This might be more stringent of a test if thats what you need (the matching records in views with the requirement that no other records with status = 0 exist in views) - but I would like to avoid this style of using a correlated subquery in real life if the tables are of an significant size:
SELECT A.id
FROM
tasks A
INNER JOIN views B
ON A.id = B.taskid
WHERE
A.status = 1
AND B.status = 1
AND NOT EXISTS (SELECT * FROM views c
WHERE c.taskid = b.taskid and c.status = 0)
Finally this is a solution that thinks conceptually more in terms of the intersection of the sets:
SELECT A.id
FROM
tasks a
INNER JOIN views a
ON A.id = b.taskid
AND b.status = 1
LEFT JOIN views c
ON a.id = c.taskid
AND c.status = 0
WHERE
A.status = 1
AND c.status is null
I just saw that forpas has just shown a different but very good solution using aggregation with a min() clause to select only the appropriate records from views for use in joining to tasks which seems like it may be the winner to me :)
If I understand you correctly, you want to get id of task , if and ONLY if it's status = 1, and there are particular records in views table with ONLY same status = 1.
Then your query would be like this:
select tasks.id
from tasks
where status =1 and not exists(
select 1
from views
where taskid=tasks.id and views.status!=tasks.status)
Check demo https://www.db-fiddle.com/f/cQfQMx5LGJN516ND2iVj8y/3
I´m trying to filter data with some categories where i get a result matching all given slug / type parameteres.
Currently i got stuck with extendending my current query to get the data with a single query. My current query looks like that:
SELECT t.slug, tc.t_id, tc.c_id
FROM tc
LEFT JOIN t ON t.id = tc.t_id
WHERE
(t.type = 'offerAges' AND t.slug = '14-16')
OR
(t.type = 'offerSportTypes' AND t.slug = 'football')
Gives me following result:
# slug t_id c_id
1 football 13 40
2 14-16 28 39
3 14-16 28 40
The result i want is that i just get the results where t_id AND c_id are matching. For example in my table the items 1 & 3.
Fiddle: https://www.db-fiddle.com/f/vQUU9C9iXj4gotE7YGDq6W/1
You can use aggregation. In this case:
SELECT tc.c_id
FROM tc JOIN
t
ON t.id = tc.t_id
WHERE (t.type = 'offerAges' AND t.slug = '14-16') OR
(t.type = 'offerSportTypes' AND t.slug = 'football')
GROUP BY tc.c_id
HAVING COUNT(DISTINCT t.type) = 2;
If you want the slugs, I would recommend using GROUP_CONCAT() to put them in a single column:
GROUP_CONCAT(t.slug)
I have a problem in my SQL Select , for example we have two users X and Y , user X want to see user Y Following so , when see his following ,
user Y want to know who users in user X (following) follow them
in this picture : https://i.imgsafe.org/d2b2d83886.png user with id :68 want to see users.id = 50 Following
SELECT users.id,users.username,
CASE WHEN follows.user_id = 68 THEN 1 END AS is_Follow
FROM users
LEFT JOIN follows
ON follows.follower_id = users.id
WHERE follows.app = 1 AND follows.user_id = 50
but this return me NULL :( what should i do ?!
Conditions on the right table of a LEFT JOIN should be on the ON clause and not on the WHERE clause :
SELECT users.id,users.username,
CASE WHEN follows.user_id = 68 THEN 1 ELSE -1 END AS is_Follow --Minus one value means NO.
FROM users
LEFT JOIN follows
ON follows.follower_id = users.id AND
follows.app = 1 AND
Another thing, what exactly are you checking? How many people follow user_id=68 ? Because by the name of the column it doesn't sounds like it.
EDIT: Try this:
SELECT users.id,users.username,
MAX(CASE WHEN follows.user_id = 68 THEN 1 ELSE -1 END) AS is_Follow --Minus one value means NO.
FROM users
LEFT JOIN follows
ON follows.follower_id = users.id AND
follows.app = 1 AND
GROUP BY users.id,users.username
I've setup a fiddle with tables and data here
I'm trying to write a single sql to check if user has reached the borrowing limit for each category.
Right now, it's done using severals sql statements called after each other.
But the way it goes is simple.
memId and id come through a querystring.
$medId = $_POST['memId']; Using 1 for this example. This is the members Id.
$id = $_POST['id']; Using 4 for this example. This is the item being lent.
After that I do:
select id, holder from collection_db where id = 4 // We have a valid item
select borrowMax from collection_db where id = (holder from the previous select) and category = 10 //Result = 2. Category indicates its a label and not a borrowable item.
select count(borrowedId) from lendings where memId = 1 and holder = (holder from the 1st query) //He's borrowed 2, under 1, so cant borrow any more. User 2 may borrow however.
if (count => borrowMax) {echo 'Cannot borrow more.';} else {echo 'Added to'}
How can this be combined into a single sql or is it best left this way?
This seems to produce a correct result set:
SELECT col1.id, col1.holder, col2.borrowMax, count(lend.borrowedId) as `count`
FROM collection_db col1
INNER JOIN collection_db col2
ON col1.holder = col2.id
INNER JOIN lendings lend
ON col1.holder = lend.holder
WHERE col1.id = $id
AND col2.category = 10
AND lend.memId = $medId
I think this combines the queries:
select max(c.borrowMax) as BorrowMax, COUNT(*)
from collection_db c join
collection_db c1
on c.id = c1.holder and c1.id = 4 and c.category = 10 join
lendings l
on l.holder = c1.holder;
It does make an assumption that the join between c and c1 does not produce duplicate rows. But you have this requirement by using = in the original query (rather than join).