I have two tables.
User table
UserId Username
1 User1
2 User2
3 User3
4 User4
17 User17
18 User18
20 User20
And One more
Customer-Support table
CSid Userslist
1 1,3
2 2
3 20,17,18
How can I get the userids of the User Table are not present in Customer-Support Table..
Using a recursive common table expression to split the values should do it:
;WITH Split AS
(
SELECT
LEFT(Userslist,CHARINDEX(',',Userslist)-1) AS Userslist
,RIGHT(Userslist,LEN(Userslist)-CHARINDEX(',',Userslist)) AS Remainder
FROM CustomerSupport
WHERE Userslist IS NOT NULL AND CHARINDEX(',',Userslist)>0
UNION ALL
SELECT
Userslist AS Userslist, NULL AS Remainder
FROM CustomerSupport
WHERE Userslist IS NOT NULL AND CHARINDEX(',',Userslist)=0
UNION ALL
SELECT
LEFT(Remainder,CHARINDEX(',',Remainder)-1)
,RIGHT(Remainder,LEN(Remainder)-CHARINDEX(',',Remainder))
FROM Split
WHERE Remainder IS NOT NULL AND CHARINDEX(',',Remainder)>0
UNION ALL
SELECT
Remainder,null
FROM Split
WHERE Remainder IS NOT NULL AND CHARINDEX(',',Remainder)=0
)
SELECT * FROM Users
WHERE UserId NOT IN (
SELECT Userslist FROM Split)
The query will return User4 for your sample data as it's the only one missing in the CustomerSupport table.
Sample SQL Fiddle
I adapted my answer from this answer by KM. Credit to the one who deserves it.
The question is answerable with the current data-model, but it is a lot of work, complicated, and a sheer waste of time.
However, with a sensible data model, it is a very simple question, so I will answer it with such a model.
We remove the UsersList field from your Customer-Support table. It should never never never be there. No, really, never.
Now, assuming that, as your example data shows, every user can have one CSid, we will add a field CSid to your User Table. This is called a foreign key. Since, as you mention, not all users are linked to the CS Table, you make sure the field allows NULL values.
Now we fill in the data:
User table
UserId Username CSid
1 User1 1
2 User2 2
3 User3 1
4 User4 NULL
17 User17 3
18 User18 3
20 User20 3
And now, to answer your question:
SELECT * FROM UserTable WHERE CSid IS NULL;
Your question is a very good example why it pays to think about your data model before messing it up. Your query is extremely simple, if your data model makes sense.
Related
I have a table MyTable with these columns:
MyTableId: int
Results: varchar(200)
And I have another table called Users:
UserId: int
Username: varchar(200)
MyTableId: int
I am cleaning up MyTable and I have a bunch of results that are now saying 'Bad Data'. I want to get a list of all the MyTableIds that have 'Bad Data' as their result and see if they are any of those Id's in the User table.
I am open to any suggestions about this.
A sample data is like so:
MyTable
MyTableId (PK) Results
1 The quick fox is fast
2 Bad Data - another piece of very bad data
3 Humpty dumpty sits on the wall
4 Hello this is a sample
5 Bad Data - this data is bad
Users
UserId (PK) Username MyTableId (FK)
1 User1 1
2 User2 2
3 User3 3
4 User4 1
5 User5 5
6 User6 2
So essentially I need to delete the bad data in MyTable with something like so:
DELETEROM MyTable WHERE Results LIKE 'Bad Data%';
This won't work because I need a script that deletes the FK data first in the Users table. I need it to be dynamic as this is just sample data.
I have User table which contains same user represented by different entities all around. For example
User Table
==========================
id name
1 John Doe
2 Doe, John
3 Nicholas Cage
4 BlackRiderXXX
5 Nicholas cage
where users John Doe, Doe, John, BlackRiderXXX are the same people. Also, Nicholas Cage and Nicholas cage are the same people. Other tables refer to user.id randomly based on which user object did the action.
For Action table it'll look like
Action Table
==========================
id user_id some_other_stuff
1 1 ...
2 2 ...
3 1 ...
4 4 ...
5 3 ...
Where the actions 1,2,3,4 are all done by John Doe.
I'll have these users merged by the user manually meaning we'd know who is whom. They'd also select which User is the one they'd like to be as their main user account so we need to know this information as well.
I'm simplifiying a bit but I have a dozen tables which are like the Action table I provided above. We have mainly two use cases on how we will need to query:
1) Find actions which are done by user X (which should check all the users entities belonging to user X)
2) Find actions and group unique users
Main point is we will be using it everywhere around the codebase on 100+ queries so we want to design it well. How can I construct a system where the query will be simple enough also powerful enough to handle different querying ways?
Thanks
PS: We are using PostgreSQL
Why not include the "main" user in the first table?
User Table
id name main_user_id
1 John Doe 1
2 Doe, John 1
3 Nicholas Cage 2
4 BlackRiderXXX 1
5 Nicholas cage 2
Then you would join on:
select . . .
from actions a join
users u
on a.user_id = u.id
where u.main_user_id = 1;
If you want this selectable per end user, then use a different table:
create table end_user_users (
end_user_users_id serial primary key,
end_user_id int references end_users (end_user_id),
end_user_user_id int references users (id),
end_user_main_user_id int references users (id)
);
Then the query would look like:
select . . .
from actions a join
end_users_users euu
on euu.end_user_user_id = a.user_id and
euu.end_user_id = $my_id
where euu.end_user_main_user_id = 1;
You can use regexp_replace(),initcap() and trim() functions to refine and extract the common name strings to be grouped, and then generate values for newly created action_id column depending on them :
with new_action0 as
(
select u.id as id,
case when strpos(u.name,',') > 0 then
initcap(trim(regexp_replace(trim(u.name),'(.*),(.*)','\2 \1')))
else
case when lower(trim(u.name))='blackriderxxx' then
'John Doe'
else
trim(initcap(u.name))
end
end as name
from action u
)
select n.id, dense_rank() over (order by n.name) as user_id
from new_action0 n;
Demo
A new decent user table can be created by using this query with create table .. as statement
Is there a way to compare bitmasks in the h2 database, similar to what has been asked in Comparing two bitmasks in SQL to see if any of the bits match ?
Having a table of users with different roles, I'd like to select all users that are programmers.
User Table
----------
ID Username Roles
1 Dave 6
2 Charlie 2
3 Susan 4
4 Nick 1
Roles Table
-----------
ID Role
1 Admin
2 Programmer
4 Designer
The select should be something like
SELECT * FROM UserTable WHERE Roles & 2 != 0
I know there is a BIT_AND function in h2 but do not know how to use it.
I was confused by the BITAND and BIT_AND functions. The select statement should look like
SELECT * FROM UserTable WHERE BITAND(Roles, 2) != 0
I have a table representing messages between users which is, roughly, as follows:
Message TABLE
(
Id INT (PK)
, User_1_Id INT (FK)
, User_2_Id INT (FK)
, ...
)
I would like to write a query which outputs a summary of how many unique conversations were held between any two users - regardless which direction the message went.
To illustrate:
Let's say we have 3 users:
User A (Id: 1),
User B (Id: 2), and
User C (Id: 3)
In the table, we have the following entries:
Id User_1_Id User_2_Id ...
1 1 2 ...
2 2 1 ...
3 1 2 ...
4 2 3 ...
5 1 2 ...
The query I desire would indicate that there were two unique conversations:
One between:
A) User A and User B, and
B) User B and User C.
What I don't want is for the query to also say that there is a conversation between:
C) User B and User A (the combination has already been covered by A, above - but in the reverse order).
This is easy if I'm working at the level of individual User Ids - but I can't figure out any kind of set-based method to achieve the outcome in single query.
Currently, the best I've been able to do is isolate that messages have been sent between users in each direction (i.e. it's returning C in addition to A and B).
UPDATE
A conversation includes all messages between any two users - regardless of the order or position of the individual messages in the context of the whole table.
I'm actually aiming to build a conversation table which probably should have been included in the original database model but was sadly left out. It wouldn't make sense to make the conversation direction-specific.
The answer would be appear to be equal to the number of rows returned by this query...
DROP TABLE IF EXISTS messages;
CREATE TABLE messages
(id INT NOT NULL AUTO_INCREMENT PRIMARY KEY
,from_user INT NOT NULL
,to_user INT NOT NULL
,INDEX(from_user,to_user)
);
INSERT INTO messages VALUES
(1, 1, 2),
(2 ,2 ,1),
(3 ,1 ,2),
(4 ,2 ,3);
SELECT DISTINCT LEAST (from_user,to_user) user1,GREATEST(from_user,to_user) user1 FROM messages;
+-------+-------+
| user1 | user1 |
+-------+-------+
| 1 | 2 |
| 2 | 3 |
+-------+-------+
2 rows in set (0.00 sec)
Would something like this work for your needs?
i would union two queries together ie, the first query puts user_1_id first, and the second puts user_2_id in position 1. Then when you union, it will distinct it for you, and you can simply count the returned rows.
The solution is to use a CASE statement which compares the size of the two columns and returns the smallest value in the first column and the largest value in the second column:
SELECT
CASE WHEN User_1_Id > User_2_Id THEN User_1_Id ELSE User_2_Id END
, CASE WHEN User_2_Id > User_1_Id THEN User_1_Id ELSE User_2_Id END
FROM
Messages
Hat-tip to #Strawberry for the answer which pointed me in the right direction.
There might be some funny results if there are users who have messaged themselves I guess - but that shouldn't happen in practice...
I need to compare two attributes in a table as a single combination.
Basically I have this table in my database with these attributes and some sample data.
Rights => RoleID,SectionID,RightID
1 2 3
1 3 5
1 5 7
2 3 5
2 1 6
so I want to pass the sectionID and RightID information belonging to a certain roleID as input in my stored procedure and return the ROleID. For example when I pass the combinations (3,5) and (1,6) my stored procedure should return RoleID 2. If there is no exact match with the combinations I pass as my input, it shouldn't return anything.
Any help in this regard is highly appreciated.
I haven't tested this but you might able to use this or amend as appropriate. The idea is that you put the joined values into temp column then use that as basis for calling the procedure. If that fails you might want to add another column to your table with the joined roleid and sectioned?
CREATE PROCEDURE GETRIGHTS
(
#param varchar(10)
)
AS
SELECT * INTO #RIGHTS FROM TABLENAME
ALTER TABLE #RIGHTS ADD JOINEDVALUES INT
SELECT #RIGHTS.JOINEDVALUE = (SELECT ROLEID + ',' + SECTIONID FROM TABLENAME WHERE #RIGHTS.JOINEDVALUE = #PARAMS)