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.
Related
I am looking for a SELECT query where I can find out the status of two users, status can be multiple things but let's keep it simple and check if both users are friends or not.
Using this query I can select every user that has x status, right now x means no status. But doing so I get the user table returned, I want the return to be true or false. Also, this query returns everyone that has x status with user x. I want to return true or false based on: if user x and x have a status, in this case friends. I hope I am not being to vague here.
SELECT
u.*
FROM User u
LEFT JOIN User_Status us
ON u.id = User_ID1
AND us.User_ID2 = 4
WHERE us.status IS NULL
User table:
ID-----first_name-----last_name-----etc...<br>**
-2--------James----------someting-------...<br>
-4----------Jack-----------someting-------...<br>
-5--------Sabrina---------someting-------...<br>
User_status table:
User_ID1-----User_ID2-----Status<br>**
-----------4-----------------2-----friends<br>
-----------2-----------------4-----friends<br>
-----------4-----------------5-----something else<br>
-----------5-----------------4-----something else<br>
Wanted result:
ID 2 (James) & ID 4 (Jack)
isFriend
true
ID 2 (James) & ID 5 (Sabrina)<br>
isFriend
false (They don't even have a status together.)
Indeed, your question is a little bit vague. Based on what I've understood, you want to find out if two users (known ID's) are friends or not?
The query below should help you with that.
SELECT
"A_USER_ID" as user_a,
"B_USER_ID" as user_b,
(
CASE
WHEN EXISTS(
SELECT *
FROM User_Status us
WHERE us.status = "friends" AND ((
us.User_ID1 = "A_USER_ID" AND us.User_ID2 = "B_USER_ID"
) OR (
us.User_ID1 = "B_USER_ID" AND us.User_ID2 = "A_USER_ID"
))
)
THEN "true"
ELSE "false"
END
) as friends
FROM
User u
WHERE
u.id = "A_USER_ID";
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)
;
i have recovered a database from a cmsms website and with Mysql i want to extract all the login information of the front-end users . i work with Heidisql
My problem user_proprerties DB is in this form:
Id UserID Type Data
1 2 email 1#2be.net
2 2 company lorme ipsum
3 2 fname testname
4 5 email& 2#2be.com
5 5 company empty
6 5 fname dolor sir amed
i want the data to be in this form:
Userid email company fname
2 1#2be.be lorem testname
5 2#2be.be emptydolor sir amed
this is the current mysql query that i have
select
cms_module_feusers_users.id,
cms_module_feusers_users.username,
cms_module_feusers_users.createdate,
cms_module_feusers_users.expires,
cms_module_feusers_properties.`data` email
from
cms_module_feusers_users
inner join cms_module_feusers_properties on cms_module_feusers_properties.userid = cms_module_feusers_users.id
where
cms_module_feusers_properties.title = 'email'
But now i'm stuck when i want the company name and fname.
(Fractionally) slower, but cleaner...
SELECT p.userid
, MAX(CASE WHEN type = 'email' THEN data END) email
, MAX(CASE WHEN type = 'company' THEN data END) company
, MAX(CASE WHEN type = 'fname' THEN data END) fname
FROM cms_module_feusers_properties p
GROUP
BY p.userid;
Add a join for each field you need
SELECT
user.id,
user.whatever,
<other stuff from cms_module_feusers_users...>
user_email.`data` as email,
user_company.`data` as company,
<other stuff from cms_module_feusers_properties...>
FROM cms_module_feusers_users user
LEFT JOIN cms_module_feusers_properties user_email ON user_email.userid = user.id AND user_email.title = 'email'
LEFT JOIN cms_module_feusers_properties user_company ON user_company.userid = user.id AND user_company.title = 'company'
<other joins from cms_module_feusers_properties...>
WHERE <conditions related to users...>
You need to use LEFT JOIN because some properties might be missing in cms_module_feusers_properties.
Also this assumes that each property appears at most once for each user.
Try this:
SELECT
cms_module_feusers_users.id,
cms_module_feusers_users.username,
cms_module_feusers_users.createdate,
cms_module_feusers_users.expires,
prop_data.data AS email,
prop_data_company.data AS company,
prop_data_fname.data AS fname
FROM
cms_module_feusers_users
INNER JOIN
(SELECT
*
FROM
cms_module_feusers_properties
WHERE
type = 'email') prop_data ON prop_data.userid = cms_module_feusers_users.id
INNER JOIN
(SELECT
*
FROM
cms_module_feusers_properties
WHERE
type = 'company') prop_data_company ON prop_data_company.userid = cms_module_feusers_users.id
INNER JOIN
(SELECT
*
FROM
cms_module_feusers_properties
WHERE
type = 'fname') prop_data_fname ON prop_data_fname.userid = cms_module_feusers_users.id
G'day
I have 2 tables
RosterTable
ID: 1
Date: 19/02/14
UserA: N
UserB: N
UserC: Y
UserD: N
UserTable
ID: 1
Username: UserA
Name: John Smith
ID: 2
Username: UserB
Name: Joe Blogs
etc...
I'm trying to search the RosterTable to see who is rostered on indicated by the 'Y' and return the coulmn name, then use that column name to find the user details in the UserTable.
I can't change these tables as they a used for something else.
Thanks for any assistance
This is a very poor database design, if I understand the question correctly. Here is one way:
select *
from UserTable ut
where exists (select 1
from RosterTable rt
where rt.UserA = 'Y' and ut.username = 'UserA' or
rt.UserB = 'Y' and ut.username = 'UserB' or
rt.UserC = 'Y' and ut.username = 'UserC' or
rt.UserD = 'Y' and ut.username = 'UserD'
);
Here is a query. It should work. The main idea is to select the rows in RosterTable that has Y value for any of the 4 users and join UserTable with the associated id that is common in both table
select * from RosterTable rt
where rt.UserA = 'Y'
or rt.UserB = 'Y'
or rt.UserC = 'Y'
or rt.UserD = 'Y'
inner join UserTable ut on ut.ID = rt.ID
Basically I have three MySQL tables:
Users - contains base information on users
Fields - describes additional fields for said users (e.g. location, dob etc.)
Data - Contains user data described via links to the fields table
With the basic design as follows (the below is a stripped down version)
Users:
ID | username | password | email | registered_date
Fields
ID | name | type
Data:
ID | User_ID | Field_ID | value
what I want to do is search Users by the values for the fields they have, e.g. example fields might be:
Full Name
Town/City
Postcode
etc.
I've got the following, which works when you're only wanting to search by one field:
SELECT `users`.`ID`,
`users`.`username`,
`users`.`email`,
`data`.`value`,
`fields`.`name`
FROM `users`,
`fields`,
`data`
WHERE `data`.`Field_ID` = '2'
AND `data`.`value` LIKE 'london'
AND `users`.`ID` = `data`.`User_ID`
AND `data`.`Field_ID` = `fields`.`ID`
GROUP BY `users`.`ID`
But what about if you want to search for Multiple fields? e.g. say I want to search for Full Name "Joe Bloggs" With Town/City set to "London"? This is the real sticking point for me.
Is something like this possible with MySQL?
I'm going with the assumption that "searching multiple fields" is talking about the Entity-Attribute-Value structure.
In that case, I propose that the first step is to create a derived query - basically, we want to limit the "EAV data joined" to only include the records that have the values we are interested in finding. (I've altered some column names, but the same premise holds.)
SELECT d.userId
FROM data d
JOIN fields f
ON f.fieldId = d.fieldId
-- now that we establish data/field relation, filter rows
WHERE f.type = "location" AND d.value = "london"
OR f.type = "job" AND d.value = "programmer"
This resulting rows are derived from the filtered EAV triplets that match our conditions. Only the userId is selected in this case (as it will be used to join against the user relation), but it is also possible to push fieldId/value/etc through.
Then we can use all of this as a derived query:
SELECT *
FROM users u
JOIN (
-- look, just goes in here :)
SELECT DISTINCT d.userId
FROM data d
JOIN fields f
ON f.fieldId = d.fieldId
WHERE f.type = "location" AND d.value = "london"
OR f.type = "job" AND d.value = "programmer"
) AS e
ON e.userId = u.userId
Notes:
The query planner will figure all the RA stuff out peachy keen; don't worry about this "nesting" as there is no dependent subquery.
I avoid the use of implicit cross-joins as I feel they muddle most queries, this case being a particularly good example.
I've "cheated" and added a DISTINCT to the derived query. This will ensure that at most one record will be joined/returned per user and avoids the use of GROUP BY.
While the above gets "OR" semantics well (it's both easier and I may have misread the question), modifications are required to get "AND" semantics. Here are some ways that the derived query can be written to get such. (And at this point I must apologize to Tony - I forget that I've already done all the plumbing to generate such queries trivially in my environment.)
Count the number of matches to ensure that all rows match. This will only work if each entity is unique per user. It also eliminates the need for DISTINCT to maintain correct multiplicity.
SELECT d.userId
FROM data d
JOIN fields f
ON f.fieldId = d.fieldId
-- now that we establish data/field relation, filter rows
WHERE f.type = "location" AND d.value = "london"
OR f.type = "job" AND d.value = "programmer"
GROUP BY d.userId
HAVING COUNT(*) = 2
Find the intersecting matches:
SELECT d.userId
FROM data d
JOIN fields f ON f.fieldId = d.fieldId
WHERE f.type = "location" AND d.value = "london"
INTERSECT
SELECT d.userId
FROM data d
JOIN fields f ON f.fieldId = d.fieldId
WHERE f.type = "job" AND d.value = "programmer"
Using JOINS (see Tony's answer).
SELECT d1.userId
FROM data d1
JOIN data d2 ON d2.userId = d1.userId
JOIN fields f1 ON f1.fieldId = d1.fieldId
JOIN fields f2 ON f2.fieldId = d2.fieldId
-- requires AND here across row
WHERE f1.type = "location" AND d1.value = "london"
AND f2.type = "job" AND d2.value = "programmer"
An inner JOIN itself provides conjunction semantics when applied outside of the condition. In this case I show "re-normalize" the data. This can also be written such that [sub-]selects appear in the select clause.
SELECT userId
FROM (
-- renormalize, many SO questions on this
SELECT q1.userId, q1.value as location, q2.value as job
FROM (SELECT d.userId, d.value
FROM data d
JOIN fields f ON f.fieldId = d.fieldId
WHERE f.type = "location") AS q1
JOIN (SELECT d.userId, d.value
FROM data d
JOIN fields f ON f.fieldId = d.fieldId
WHERE f.type = "job") AS q2
ON q1.userId = q2.userId
) AS q
WHERE location = "london"
AND job = "programmer"
The above duplicity is relatively easy to generate via code and some databases (such as SQL Server) support CTEs which make writing such much simpler. YMMV.
If I understood you right, this is what you want:
FROM `users`,
`fields`,
`data` `location`
`data` `name`
WHERE `location`.`Field_ID` = '2'
AND `location`.`value` LIKE 'london'
AND `location`.`Field_ID` = `fields`.`ID`
AND `name`.`Field_ID` = 'whathere? something for its name'
AND `name`.`value` LIKE 'london'
AND `name`.`Field_ID` = `fields`.`ID`
AND `users`.`ID` = `data`.`User_ID`
I'd prefer joins though
Well here you hit one of the downsides of the EAV you are using
SELECT u.ID, u.username,u.email, d1.value, f1.Name, d2.Value, f2.name
FROM `users` u,
inner join data d1 On d1.User_id = u.id
inner join data d2 On d2.User_id = u.id
inner join fields f1 on f1.id = d1.field_id
inner join fields f2 on f2.id = d2.field_id
WHERE d1.Field_id = '2' and d1.Value = 'london'
and d2.field_id = '??' and d2.value = 'Joe Bloggs'
GROUP BY `users`.`ID`
Messy isn't it? Bet you can't wait to go for, four or five values. Or think about (Forename = Joe Or surname = Bloggs) and City = London...