SELECT with condition on second table - mysql

I'm trying to select records from 3 tables using a JOIN which is working well but I now need to add some additional conditions to the SELECT which I can't figure out. My current select works like this:
SELECT user.*, address.*, state.* FROM user
LEFT JOIN address ON user.id = address.user_id
LEFT JOIN state ON user.id = state.user_id
Now, the address and state could have multiple records but both tables have a bit field to indicate that they are the primary record and that's the one I want to select. I have tried adding a WHERE address.state = b'1' to the statement but it only returns those records that have a primary record, what I would ideally like to do is select the top record from the address/state table sorted by the primary field so the primary will be selected if it exists but the next record will be selected if there is no primary.
How can I achieve this with MySQL 5?

Add the condition to your LEFT JOIN:
LEFT JOIN address ON ( user.id = address.user_id AND address.state = b'1' )
The left join will only return rows that match this criteria, but you will still get users without a primary address.

Related

Mysql : how to retrieve a list of row where one field doesn't contain a specific value from an ENUM

I have a table which lists users albums.
PRIMARY KEY, USER KEY, TYPE and TITLE.
The TYPE field is an ENUM.
Normally every user has an entry of type 'avatar' created automatically upon registration but it seems one hasn't.
I want a query that can output the users key which don't have any 'avatar' type entry associated.
I thought this query would do the trick :
SELECT * FROM (
SELECT DISTINCT user_key FROM `album` WHERE 1
) a
OUTER JOIN (
SELECT user_key FROM `album` WHERE type = 'avatar'
) b
ON a.user_key = b.user_key
The goal is to select every distinct user from the table, then every user which has an 'avatar' entry and finally to do an outer join in order to retrieve only the users which don't have that entry.
With an inner join I get the right user list that have this entry (which doesn't solve my problem) but with an outer join I get a syntax error.
Did I get something wrong with outer joins or is there a smarter way to get what I want ?
Thank you.
There is no "OUTER JOIN" in MySQL ! , you should use "LEFT | RIGHT JOIN", and for a full outer join you can UNION them like this :
SELECT * FROM table1 a
LEFT JOIN table2 b ON a.user_key = b.user_key
UNION
SELECT * FROM table1 a
LEFT JOIN table2 b ON a.user_key = b.user_key
but it seems no need to joining selects !, If you want to get the list of users who have not 'avatar' in type field, you shoud do like this :
SELECT DISTINCT(user_Key) FROM albums WHERE Type <> 'avatar'
AND user_key NOT IN (Select DISTINCT(user_key) FROM albums WHERE Type = 'avatar');
There is No need to use "NOT IN" for ENUM type because ENUM type gets only one value and SET type gets some values
If i understand the qurstion correctly, you just want the user_key column for all users whos type is not 'avatar'
SELECT DISTINCT(user_key) FROM album WHERE type IS NOT IN ('avatar')

SQL making new table from existing tables

I have this very basic problem and just can't figure out how to do it. I have two tables.
The first one, users, contains two columns: id which is just number representing a person and sex. Second column doesn't matter now.
The other table, orders has columns: id_user, time, state. The id_user refers to id in the first table. state has three different values (finished, canceled, new). I need to make a table that would show count of finished state (how many finished states one person has) next to the id of that person. I can run this thing:
select * , count(state) as CountOfFinished from orders
where state = 'finished'
group by id_user;
to show me that information, but i need to have a table that would show id,sex, CountOfFinished.
I copied the first table to a new one, but don't know how to add the CountOfFinished column next to these two. I don't even know how to make a column out of it so I can join it or something.
Any idea what should I do?
You don't need a new table. What you want is a JOIN, or in this case, a LEFT JOIN:
SELECT
u.id,
u.sex,
ISNULL(COUNT(o.state), 0) as CountOfFinished
FROM users u
LEFT JOIN orders o
ON o.id_user = u.id
AND o.state = 'finished'
GROUP BY
u.id, u.sex
The above query will list all users and the number of finished orders. If you want to list only users with at least one finished order, use INNER JOIN.
To insert into a new table, create the table first and use INSERT INTO:
CREATE TABLE FinishedOrderCountByUser(
UserId INT,
Sex CHAR(1),
CountOfFinished INT
)
INSERT INTO FinishedOrderCountByUser(UserId, Sex, CountOfFinished)
SELECT
u.id,
u.sex,
ISNULL(COUNT(o.state), 0) as CountOfFinished
FROM users u
LEFT JOIN orders o
ON o.id_user = u.id
AND o.state = 'finished'
GROUP BY
u.id, u.sex

mysql left join with multiple where columns

I have a customer table and an address table. Each customer can have multiple entries in the address table, but only one of those entries can be marked as 'primary'. I've put together the query to pull up the customer and their primary address as follows:
SELECT * FROM customers LEFT JOIN addresses
ON customers.cust_id = addresses.cust_id
WHERE customers.status = 1 AND addresses.primary = 1
I've found a flaw in that if the customer has not yet added an address to their account, they will not appear because there is no 'primary' address.
What's the best way to work around this?
SELECT *
FROM customers
LEFT JOIN addresses
ON customers.cust_id = addresses.cust_id
AND 1 = addresses.primary
WHERE customers.status = 1
Try modifying the query to AND (addresses.primary = 1 OR addresses.primary IS NULL)
Simply include the left side data when there is no address.
In the example below I use the primary field, but any field of the addesses table
is null in a left join clause when there is no matching key.
SELECT * FROM customers LEFT JOIN addresses
ON customers.cust_id = addresses.cust_id
WHERE customers.status = 1 AND
(addresses.primary = 1 OR addresses.primary IS Null)

MySQL select rows that do not have matching column in other table

I can't seem to figure this out so far. I am trying to join two tables and only select the rows in table A that do not have a matching column in table B. For example, lets assume we have a users table and a sent table.
users table has the following columns: id, username
sent table has the following columns: id, username
I want to select all rows from users where username does not exist in sent table. So, if tom is in users and in sent he will not be selected. If he is in users but not in sent he will be selected. I tried this but it didn't work at all:
SELECT pooltest.name,senttest.sentname
FROM pooltest,senttest
WHERE pooltest.name != senttest.sentname
Typically, you would use NOT EXISTS for this type of query
SELECT p.Name
FROM pooltest p
WHERE NOT EXISTS (SELECT s.Name
FROM senttest s
WHERE s.Name = p.Name)
An alternative would be to use a LEFT OUTER JOIN and check for NULL
SELECT p.Name
FROM pooltest p
LEFT OUTER JOIN senttest s ON s.Name = p.Name
WHERE s.Name IS NULL
Note that the implicit join syntax you are using is considered obsolete and should be replaced with an explicit join.
Try this SQL:
SELECT users.username
FROM users
LEFT JOIN sent ON sent.username = users.username
WHERE sent.username IS NULL;
The better way in my opinion would be:
SELECT users.username
FROM users
LEFT JOIN sent ON sent.id = users.id
WHERE sent.id IS NULL;
As both the id fields, would be indexed (primary key I would have thought) so this query would be better optimised than the first one I suggested.
However you may find my first suggestion better for you, it depends on what your requirements are for your application.
May be this one can help you ....
I had also the same problem but Solved using this this query
INSERT INTO tbl1 (id,name) SELECT id,name from tbl2 where (name) not in(select name from tbl1);
hope this one will solve your problem

MySQL subquery - Find only first record in a LEFT JOIN

I'm trying to display a list of member records, and I have a few tables I'm using to display what I need.
That's the easy part. The part I need help with is with a table that has many records to each member record: Login history
I want to display only the first row for each member record, that exists in the Login History table. Alternatively, I may want to flip flop and display the last record in the Login History table, as well.
here's what I've got so far:
SELECT m.memberid, m.membername, m.gender, mp.phone
FROM tbl_members m,
tbl_members_phones mp,
tbl_members_addresses ma
WHERE m.defaultphoneid = mp.phoneid
AND m.defaultaddressid = ma.addressid
So that returns what's expected.
The 2 columns from tbl_members_login_history I'd like to add to the returned result are: mh.loggedtime, mh.ipaddy
I know adding the tbl_members_login_history as a LEFT JOIN would return duplicates, so I'm thinking there must be a Subquery necessity here, in order to return just the 1st record for that memberid that exists in tbl_members_login_history.
What I'm worried about is if no record in the history table exists, I still want to display that member info, but leave the history columns as NULL.
Would this be a subquery incident? and if so, how does one add that type of LIMIT?
This is the greatest-n-per-group problem, which is asked frequently on Stack Overflow.
Here's how I would solve it in your scenario:
SELECT m.memberid, m.membername, m.gender, mp.phone, mh.loggedtime, mh.ipaddy
FROM tbl_members m
INNER JOIN tbl_members_phones mp ON m.defaultphoneid = mp.phoneid
INNER JOIN tbl_members_addresses ma ON m.defaultaddressid = ma.addressid
LEFT OUTER JOIN tbl_members_login_history mh ON m.memberid = mh.memberid
LEFT OUTER JOIN tbl_members_login_history mh2 ON m.memberid = mh2.memberid
AND mh.pk < mh2.pk
WHERE mh2.pk IS NULL;
That is, we want mh to be the most recent row in tbl_member_login_history for the given memberid. So we search for another row mh2 that is even more recent. If none more recent than the mh row is found, then mh2.* will be NULL, so mh must be the most recent.
I'm assuming this table has a primary key column that contains increasing values. For this example, I assume the column name is pk.
Using LEFT OUTER JOIN for both references to the login history table means that the m row will be reported even if there is no matching row.
add like this
LEFT OUTER JOIN (SELECT member_id, MAX(LAST_LOGIN_DATE) from tbl_members_login_history) Last_Login ON Last_Login.memberid = m.memberid
PS. LAST_LOGIN_DATE is pseudo column, you can try your restictive column