MySql If statements - sql

I have a simple table that logs simple events an administrator does. Nothing complicated.
One of the columns is userid, so I can reference the user's name from the users table:
SELECT u.username FROM `users` u, `history` h WHERE u.userid = h.userid
My issue is that the internal system also logs events (just like a user), but there is no userid related to the internal system. It is simply logged as zero, in the record.
Is there a way to modify the query to reflect this? I've tried a LEFT JOIN, but that doesn't let me specify "system" as the username. The other thing i can do is enter a new user into the user's table, and call it "Internal System". But I really don't want to do that.
Is it possible to do this from the query level?

Use:
SELECT COALESCE(u.username, 'SYSTEM') AS username,
FROM HISTORY h
LEFT JOIN USERS u ON u.userid = h.userid
COALESCE will return the first non-NULL value, so if you LEFT JOIN onto USERS and username is NULL--then "system" or whatever you prefer will appear.

Related

SQL - Select ids that appear at least once in other table

I'm trying to get a list of Users that appear at least once in OtherTable. The following is my very inefficient HQL query using Grails. In general, there will only be at most a few hundred users that will be run in the query but potentially a million references to those users in OtherTable.
List<User> users = User.executeQuery("select user " +
"from User as user where user.id = any(" +
"select otherTable.user.id from OtherTable as otherTable)")
How can I make this query more efficient?
This SQL might be more effcient,
select distinct u.id from user as u
inner join other_table ot
on u.id = ot.id
Here is an HQL,
select distinct user
from User as user
inner join user.otherTable as ot
Using Criteria API
User.createCriteria().listDistinct {
createAlias("otherTable","ot")
eq('id','ot.id')
}
Both the above would require proper mapping of your domain classes. In case, you don't have that, OtherTable, mapped in User. Try this,
select distinct user from User user, OtherTable ot
where user.id = ot.user_id
You may have noticed that we're avoiding full table scans here, completely; and it's a single query -- unlike the one you posted, which uses a subquery. Joining both entities/tables with id should be more efficient -- assuming id columns are indexed.
Try the following query:
List<User> users = User.executeQuery("select user " +
"from User as user where" +
"user.id in (select distinct otherTable.user.id from OtherTable as otherTable)")
Hope it will help!

Select a user by their username and then select data from another table using their UID

Sorry if that title is a bit convoluted... I'm spoiled by an ORM usually and my raw SQL skills are really poor, apparently.
I'm writing an application that links to a vBulletin forum. Users authenticate with their forum username, and the query for that is simple (selecting by username from the users table). The next half of it is more complex. There's also a subscriptions table that has a timestamp in it, but the primary key for these is a user id, not a username.
This is what I've worked out so far:
SELECT
forum.user.userid,
forum.user.usergroupid,
forum.user.password,
forum.user.salt,
forum.user.pmunread,
forum.subscriptionlog.expirydate
FROM
forum.user
JOIN forum.subscriptionlog
WHERE
forum.user.username LIKE 'SomeUSER'
Unfortunately this returns the entirety of the subscriptionlog table, which makes sense because there's no username field in it. Is it possible to grab the subscriptionlog row using the userid I get from forum.user.userid, or does this need to be split into two queries?
Thanks!
The issue is that you are blindly joining the two tables. You need to specify what column they are related by.
I think you want something like:
SELECT * FROM user u
INNER JOIN subscriptionlog sl ON u.id = sl.userid
WHERE u.username LIKE 'SomeUSER'
select * from user u JOIN subscriptions s ON u.id = s.id where u.username = 'someuser'
The bit in bold is what you want to add, it combines the 2 tables into one that you return results from.
try this
SELECT
forum.user.userid,
forum.user.usergroupid,
forum.user.password,
forum.user.salt,
forum.user.pmunread,
forum.subscriptionlog.expirydate
FROM
forum.user
INNER JOIN forum.subscriptionlog
ON forum.subscriptionlog.userid = forum.user.userid
WHERE
forum.user.username LIKE 'SomeUSER'

Login DAO sql statement involving multiple joins

I am trying to create a query that will return through DAO whether the inputted username and password is correct. I'm using java for DAO implementation as well as JSF.
I have the following tables:
LOGIN: username (pk)
BUSINESS: username (fk), password
CUSTOMER: username (fk), password
What I'm trying to do is create multiple joins so that when a user goes to log in, their stored username defines what type of account they have. By pulling the username, the username is looked for in both the BUSINESS and CUSTOMER and when found, the password is then compared. I tried the following statement:
SELECT l.USERNAME
FROM ITKSTU.BUSINESS b
JOIN ITKSTU.LOGIN l
ON l.USERNAME=b.USERNAME
JOIN ITKSTU.CUSTOMER c
ON c.USERNAME=l.USERNAME
WHERE l.USERNAME='user111' AND (b.PASSWORD='aaa' OR c.PASSWORD='aaa');
Yet it returns nothing. Any possible suggestions?
I have replicated the same here and it looks like it is working. Could you check?
http://sqlfiddle.com/#!2/f253d/2
Thanks
If I understood correctly, what you need is to distinguish a user's type, whether he/she is in business table or customer table. Then, check the password correctness.
Then, again if I am not wrong, you should have an entry for all users in login table, then each one of them should take place EITHER in businees OR customer table.
Let's assume we have records such as:
INSERT INTO login VALUES ('TEST');
INSERT INTO login VALUES ('TEST2');
INSERT INTO business VALUES ('TEST','PASSWORD123');
INSERT INTO customer VALUES ('TEST2','PASSWORD1234');
I think you may solve the problem with the following query. Let's test with the user named "TEST2":
SELECT b.username AS business_user, c.username AS customer_user
FROM login l
LEFT JOIN business b ON b.username = l.username
LEFT JOIN customer c ON c.username = l.username
WHERE l.username = 'TEST2' AND (b.password = 'PASSWORD1234' OR c.password = 'PASSWORD1234');
This query will return 2 columns as you notice: first one will return null as the user is not in business table. The second one will give you the username and label it as "customer_user". Therefore, if you check each column and determine which one is null, then you will know where the user actually belongs to (either to business or customer table).
The trick here is to begin with login table ("FROM login") and use LEFT JOIN, instead of JOIN. Here is a quick tip about joins and their differences, if you need it: http://www.firebirdfaq.org/faq93/

What's wrong with this code? Issue with copying data across tables

insert into Permission (UserID, perm, Login) select UserID, 0, Login from Users
What happens: Copy data across tables and inserts 0 as a default value for 'perm' column. However, I need to run this code every time the software creates its form. So it keeps adding everything it already have.
Workaround: DELETE FROM Permission WHERE perm=0 --before running the insert code. This will make sure not to delete users who have Perm=1 (permission to alter something).
Issue: So I run the delete code above before running the insert. But since it's a frequent routine it will double the user already contained in the table Permissions (i.e.: user Admin will have perm=0 and perm=1). Is there anyway to detect if the user already exist and skip it or something?
What you could do is
insert into Permission(UserID,perm,Login)
select UserID, 0, Login
from Users
where UserID NOT IN(select UserID from Permission);
Basically what that does is inserts them in if they aren't already there.
This will only insert records that are not already in Permission table by the combination of UserID and Login. Probably, UserID alone is enough if Login is stored as redundant (not-normalized data).
insert into Permission (UserID, perm, Login)
select U.UserID, 0, U.Login
from Users U
left join Permission P on P.UserID = U.UserID and P.Login = U.Login
where P.Login is null
The permission matrix is usually expressed in one of two ways:
bit mask - but this gets into scalability issues real quick, so your Perm field contains a mask of all "allowed" bits
UserId - PermissionId - Access (bit). This is what I assume your table has (the tuple UserId/PermissionId) and hence the LEFT JOIN form on two fields.
Sure, this will insert only records that do not have a permission record already.
INSERT INTO Permission (UserID, perm, Login)
SELECT u.UserID, 0, u.Login
FROM Users u
LEFT OUTER JOIN Permission p ON u.UserID = p.UserID
WHERE p.UserID IS NULL

Get the inverse of a join?

I am using SQL Server 2005. I have three tables - Users, Groups, and GroupUsers. GroupUsers contains the two PKs for a many-to-many relationship.
I have a view to get all the user information for a group as follows:
SELECT * FROM GroupUsers JOIN Users ON GroupUsers.UserID = Users.UserId
I want to create the inverse of this view - I want a list of all of the users NOT attached to a specific group. The following query would accomplish this:
SELECT * FROM Users WHERE UserID NOT IN
(SELECT UserID FROM GroupUsers WHERE GroupID=#GroupID)
However I don't want to have to specify the group, I want to know how to turn this into a view that joins the GroupID and then the UsersID and all the user info, but only for non-attached users.
I'm not sure how to do this, maybe something with the EXCEPT operator?
UPDATE:
I think this is my solution, unless someone comes up with something better:
SELECT
G.GroupId,
U.*
FROM
Groups G
CROSS JOIN
Users U
WHERE
U.UserId NOT IN
(
SELECT
UserId
FROM
GroupUsers
WHERE
GroupId=G.GroupId
)
You can use a left outer join to grab all of the users, then, blow away any user where there's a group attached. The following query will give you just the list of users where there's no group to be had:
select
u.*
from
users u
left outer join groupusers g on
u.userid = g.userid
where
g.userid is null
If you want to find all users not in a particular group:
select
u.*
from
users u
left outer join groupusers g on
u.userid = g.userid
and g.groupid = #GroupID
where
g.userid is null
This will only exclude the users in that particular group. Every other user will be returned. This is because the groupid condition was done in the join clause, which limits the rows joined, not returned, which is what the where clause does.
If I understand it correctly, you will have to do a cartersian result of users & groups and reduce the result derived from GroupUsers.
That will give you records of users which do not have any groups attached to it.
I apologize if I didn't understand the question correctly.
EDIT: Cartesian result will give you users * groups. You will have to subtract GroupUsers from it. I am sorry, I do not have SQL ready for it & can't try it out at this point.
I couldn't figure out how to get previous version to work via active record, got some of the way there but had to write an SQL in statement. I believe this also accomplishes the same thing.
SELECT * FROM Users WHERE UserID NOT IN
(SELECT U.UserID FROM GroupUsers AS G, Users as U WHERE G.UserID <> U.UserID)
Couldn't test however this query in rails worked just fine:
# Gets Pre-Clients. Has client information but no project attached
Contact.joins(:client).includes(:projects => :primary_contact).
where("contacts.id NOT IN (select contacts.id from contacts,
projects where projects.primary_contact_id = contacts.id)")
Thanks for the post got me 90% of the way there.