How to use multi table join query efficiently in SQL? - sql

I have Problem statement in Apache Phoenix in which I need to combine three tables for the result.
I have three views over Hbase table, Schema is as follow
Table group:-
pk | Title | ownerId | data
Table Members:-
pk | parentId | Email | data
Table userinfo:-
pk | Email | First Name | Last Name
Now, I want to fetch groups whose title matches with input string if not matched then want to fetch groups whose members have a name that matches with the input string.
I already tried query as follow:-
select * from Group where pk like 'Prefix_%'
and (TITLE like '%A%'
or (OWNER_ID in
(
select parentId from MEMBERS where EMAIL in
( select distinct(EMAIL) from USER_INFO
where pk like 'PREFIX%' and
( FIRST_NAME like '%A%' or LAST_NAME like '%A%')
)
)
) ) order by TITLE limit 5;
But, it's taking too much time also tried Left Join Query with similar but not give expected result.
Please Suggest how can I improve this?

Related

DB queries with "In" seem to be sorted

There are clients(companies) and contacts in two tables. Both contacts and clients have their own fields. But they all have an id that is a primaryKey. In addition, there are "links" between clients and contacts - each client can be assigned a contact and vice versa. There is a third table for this, called 'assignment', which has only two fields - company id and contact id.
Suppose we have linked a contact with id 3 to a company with id 12076. Next, we have linked a contact with id 10, and the last contact with id 5. Сheck our result:
SELECT contactId FROM assignment WHERE companyId = 12076;
The result is correct -
After these steps, at some point I need to get the FIELDS of contacts associated with the company I need. There is a company 12076, I need to get all the contact fields associated with it. I made a request like this:
SELECT id, fullName FROM contacts WHERE contacts.rowid IN (SELECT contactId FROM assignment WHERE companyId = 12076);
This request displays the contacts I need and their fields. Exactly 3 contacts, but there is one problem - they are displayed in sorted order, sorted by id.
I need the contact fields to be displayed in the order in which they were added. How can i dow this? Maybe i need to use JOIN?
By default an SQLite table has a Rowid column. We can use this column in ORDER BY.
If we want the ContactId's in the order they were inserted into the table contacts we can join onto contacts and order by it's Rowid.
See [https://www.sqlitetutorial.net/sqlite-autoincrement/][1]
create table companies(id int);
create table contacts (id int);
create table assignment(companyId int,contactId int);
insert into companies values(12076);
insert into contacts values(10),(3),(5);
insert into assignment values (12076,3),(12076,10),(12076,5);
SELECT a.contactId
FROM assignment a
JOIN contacts c
on a.contactId = c.id
WHERE companyId = 12076
order by c.Rowid;
| contactId |
| --------: |
| 10 |
| 3 |
| 5 |
db<>fiddle here

SQL Query to fetch the customers registered in the DB without email address(CS can have phonenumber and email in the same field but duplicating)

I need help with writing this query please ,
in the Database - the customer is registered twice , one row with the email address in the VALUE field and the other row with phone number in the SAME VALUE field .
I want to fetch customer who DO NOT HAVE email address in the VALUE FIELD .
For example , I want to fetch only the last row from the list shown in the figure I shared.
Appreciate your help!
I tried creating multiple SELECT queries , but still not getting the accurate values.
Without seeing table schemas or example data, I'm making an assumption here that you have a field that is common to both rows so you know the customer row with the email value and the customer row with the phone value are linked to the same customer. For the purposes of this example, I'm going to call that field "customer_number".
I'd suggest a query that utilises an auxiliary statement like this:
WITH customers_with_emails AS (
SELECT customer_number
FROM customers
WHERE customer_value LIKE '%#%'
)
SELECT *
FROM customers
WHERE customer_number NOT IN (
SELECT customer_number
FROM customers_with_emails
);
This will return customers with phone numbers, who do not also have an email address.
I suggest that you use the following query, modified with the exact column and table name. We use string_agg to coalesce all the value fields for the same customer id and only show them if none of them contain an # sign.
create table customers(
id int,
name varchar(25),
value varchar(25));
insert into customers values
(1,'Mr A','1234'),
(1,'Mr A','a#b.c'),
(2,'Mr B','6789');
select
id,
max(name) "name",
string_agg(value,', ')
from
customers
group by
id
having
string_agg(value,', ') NOT LIKE '%#%';
id | name | string_agg
-: | :--- | :---------
2 | Mr B | 6789
db<>fiddle here

Create view from table with multiple primary key

I've a table like this one:
Column | Type | Modifiers
username | character varying(12) | not null
electioncode | integer | not null
votes | integer | default 0
PRIMARY KEY (username, electioncode)
i need to create a view with username, electioncode, max(votes)
if i use this query it works fine but without username:
SELECT electioncode, max(votes) from table group by electioncode;
if i add username it asks me to add it into the group by but if i do that it gives me the entire table instead of just the username-electioncode-maxvotes
Do you want to get username associated with this number of votes? Or any username in given election code?
If the first:
SELECT
DISTINCT ON ( electioncode )
*
FROM table
ORDER BY electioncode, votes desc;
if the other:
SELECT
electioncode,
min(username),
max(votes)
FROM
table
GROUP BY electioncode;
Your username field seems to be unique. Every record has different username (I am assuming) thus when you group by username it will give you all the records. What you are trying to do has a logic issue not syntax issue.
A suggestion: You want to write on a piece of paper the output you would like to see and then construct the query... If you want Username, Electioncode and max (votes) then imagine how you would display the data where two usernames - user1 and user 2 who have electioncode 001 and voted 1 each? How would you display this?

Select all items in a table that do not appear in a foreign key of another table

Take for example an application which has users, each of which can be in exactly one group. If we want to SELECT the list of groups which have no members, what would be the correct SQL? I keep feeling like I'm just about to grasp the query, and then it disappears again.
Bonus points - given the alternative senario, where it's a many to many pairing, what is the SQL to identify unused groups?
(if you want concrete field names:)
One-To-Many:
Table 'users': | user_id | group_id |
Table 'groups': | group_id |
Many-To-Many:
Table 'users': | user_id |
Table 'groups': | group_id |
Table 'user-group': | user_id | group_id |
Groups that have no members (for the many-many pairing):
SELECT *
FROM groups g
WHERE NOT EXISTS
(
SELECT 1
FROM users_groups ug
WHERE g.groupid = ug.groupid
);
This Sql will also work in your "first" example as you can substitute "users" for "users_groups" in the sub-query =)
As far as performance is concerned, I know that this query can be quite performant on Sql Server, but I'm not so sure how well MySql likes it..
For the first one, try this:
SELECT * FROM groups
LEFT JOIN users ON (groups.group_id=users.group_id)
WHERE users.user_id IS NULL;
For the second one, try this:
SELECT * FROM groups
LEFT JOIN user-group ON (groups.group_id=user-group.group_id)
WHERE user-group.user_id IS NULL;
SELECT *
FROM groups
WHERE groups.id NOT IN (
SELECT user.group_id
FROM user
)
It will return all group id which not present in user

SQL Select based on Link Field

I feel like an idiot asking this...
Table 1: users
id serial
person integer
username char(32)
Table 2:persons
id serial
name char(16)
Can I run a query that returns the name field in persons by providing the username in users?
users
1 | 1 | larry123
persons
1 | larry
2 | curly
SQL?
select name from persons where users.person=persons.id and users.username='larry123';
with the desired return of
larry
I have been doing it with two passes until now and think maybe a nested select using a join is what I need
1 | larry
It sounds like you're asking how to do a join in SQL:
SELECT
name
FROM
users JOIN persons ON (users.person = persons.id)
WHERE
users.username = 'larry123';
that is almost the query you wrote. All you were missing was the join clause. You could also do that join like this:
SELECT name
FROM users, persons
WHERE
users.person = persons.id
AND users.username = 'larry123';
I suggest finding a well-written introduction to SQL.