I have three tables: users, contacts, and groups. I want to find all the contacts of a user, and then from those selected contacts, I want to exclude those contacts of that user that have a particular group_id found in the groups table.
My groups table is structured as such:
id (primary key)
group_id (a foreign key to a table contain general group info)
user_id (a foreign key to the users table)
My contacts table is structured like this:
id (primary key)
user_id (a foreign key to the `users` table of the user who added the contact)
contact_id (a foreign key to the `users` table of the added contact)
My current, not-working query is this:
"""SELECT c.*, u.*
FROM contacts c
LEFT JOIN groups g ON c.contact_id = g.user_id
INNER JOIN users u on u.id = c.contact_id
WHERE c.user_id = %s AND
<not sure what further constraints to place on query>""", (user_id, group_id)
From my understanding, the LEFT JOIN is certainly incorrect, and given that it is incorrect, I have not yet added any more constraints in the WHERE clause.
What is the best way to accomplish this?
Thank you.
Assuming that the LEFT JOIN is correct and you want to include contacts who do not belong to any group, you can try the following query:
select
c.*,
u.*
from users u
join contacts c
on u.id = c.user_id
left join groups g
on c.contact_id = g.user_id
where
c.user_id = %s
and g.group_id not in (<your groups here>)
Where your list of groups would be a comma-separated list of identifiers. I don't know if the PostgreSQL python driver contains any function for easily formatting this or not, but that is the idea.
To answer your secondary question in your comment (how to get contacts without group AND contacts in excluded group), you probably need to use a union:
select
c.*,
u.*
from users u
join contacts c
on u.id = c.user_id
left join groups g
on c.contact_id = g.user_id
where
c.user_id = %s
and g.group_id is null
union
select
c.*,
u.*
from users u
join contacts c
on u.id = c.user_id
join groups g
on c.contact_id = g.user_id
where
c.user_id = %s
and g.group_id = %d
Related
I have the following SQL:
SELECT id, user_id, coordinates
FROM fields
WHERE id IN (SELECT field_id FROM transactions WHERE id IN (11,10,12))
There are 2 tables: transactions and fields. Both of them have their own id field. However, in transactions there's also a field to connect each row to the fields.id called field_id. I have a list of transactions.id, and I would like to obtain a few fields from table fields, but I would like to obtain too the transactions.id associated. For example for the first row it would be:
fields.id (for transactions.id=11), fields.user_id (for transactions.id=11), fields.coordinates (for transactions.id=11), 11
and so on.
Is this possible? I will do these queries using python with postgresql v14.
If I understood the question correctly
SELECT * FROM fields f
join transactions t on f.id = t.field_id
WHERE t.id in (11,10,12)
SELECT t.id as lower_id, f.id as higher_id FROM fields f
join transactions t on f.id = t.field_id
WHERE t.id in (11,10,12)
I have a database in SQL Server which contains huge numbers of tables. But each table has 'id' and 'value'. I want to join all the tables which their names contain a certain text (e.g., 'ts2') based on their id (id is a common key). So my desired table should have 'id' and the 'values' of each table with the name of the table. For example:
TableAts2:
id,
value
TableBts2:
id,
value
Tablts2C:
id,
value
...
My desired table:
mytable:
id, value_TableAts2,value_TableBts2, value_Tablts2C
Some source datatables
CREATE TABLE TableAts2 (id INT, value INT);
INSERT INTO TableAts2 VALUES (1,1), (2,2);
CREATE TABLE TableBts2 LIKE TableAts2;
INSERT INTO TableBts2 VALUES (1,11), (3,33);
CREATE TABLE TableCts2 LIKE TableAts2;
INSERT INTO TableCts2 VALUES (2,222), (3,333);
Build the query text
SELECT
CONCAT( 'SELECT id, ',
GROUP_CONCAT(table_name, '.value value_',table_name) ,
'\nFROM (',
GROUP_CONCAT('SELECT id FROM ',table_name SEPARATOR ' UNION '),
') ids\nLEFT JOIN ',
GROUP_CONCAT(table_name, ' USING (id)' SEPARATOR '\nLEFT JOIN ')
)
INTO #sql
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = DATABASE();
Check the query built
SELECT #sql;
SELECT id, TableAts2.value value_TableAts2,TableBts2.value value_TableBts2,TableCts2.value value_TableCts2
FROM (SELECT id FROM TableAts2 UNION SELECT id FROM TableBts2 UNION SELECT id FROM TableCts2) ids
LEFT JOIN TableAts2 USING (id)
LEFT JOIN TableBts2 USING (id)
LEFT JOIN TableCts2 USING (id)
Execute the query
PREPARE stmt FROM #sql;
EXECUTE stmt;
DROP PREPARE stmt;
id
value_TableAts2
value_TableBts2
value_TableCts2
1
1
11
null
2
2
null
222
3
null
33
333
db<>fiddle here
Of course the query needs in a check that the table contains both id and value columns (by according subquery to INFORMATION_SCHEMA.COLUMNS).
i think this should work fine for you :
select tableAts1.* , TableBts2.* , Tablts2C.*
from tableAts1
inner join TableBts2 on tableAts.id = TableBts2.id
inner join Tablts2C on tableBts2.id = tablts2C.id
First, you need to insert one column in each table.
For example
TableAts2:
id,
user_id,
value
TableBts2:
id,
user_id,
value
Tablts2C:
id,
user_id,
value
...
Second, you need to join each table with user_id.
Now please run this sql command:
select t.value_TableAts2 as value_TableAts2, t.value_TableBts2 as value_TableBts2, Tablts2C.value as value_Tablts2C from (select TableAts2.value as value_TableAts2, TableBts2.value as value_TableBts2, TableAts2.user_id as user_id from TableAts2 left join TableBts2 on TableAts2.user_id = TableBts2.user_id) as t left join Tablts2C on t.user_id = Tablts2C.user_id
Result :::
Your desired table:
id, value_TableAts2,value_TableBts2, value_Tablts2C
I'm working with PostgreSQL 10 and Python 3. I know how to o simple selects or joins, buy I have issues when need to combine 4 tables related 2 by 2.
I mention, that I use Phyton, in case is necessary to combine queries using code.
I have the following tables: Company, CompanyLogo, Product, ProductImage, with the following
Relations:
Company Logo O1O with Company
Product has FK to Company
ProductImage FK with Product
Structure
Company
Id | slug
1 1
Logo
Id | path | company_id
1 url 1
-----------
Product
Id | company_id
1 1
2 1
ProductImage
Id | path | product_id
1 url 1
2 url 1
3 url 1
I need:
Get list of all companies, and for each company get:
the company slug
the logo
up to 3 products and their first image
Get one company based on id and:
the company slug
the logo
all product and their first image
The problem here is, that you have this restrictions for the numbers of products or images.
I tried to solve this in subqueries selecting only the first n products/pictures per company/product by determining the count of lower IDs. An ID only matches if there are no more than n IDs less or equal the ID for the same company or product. In other words the products/images with the n (or less than n, if there aren't more) lowest IDs per company/product will make it in the result. For logo, if I got you right, company_id is unique, so that step isn't needed there. (In case I misunderstood that, It'd be a subquery analog to the others.) In case of pictures that indeed fetches the first picture, given that the ID is automatically incremented. So if "first" in your question had to be taken literally, that's given too.
I assumed you want to see a company/product even, if there is no logo/product/picture for it. So I used LEFT JOINs.
Two sub queries, one for product, one for productimage:
SELECT c.id,
c.slug,
l.id,
l.path,
p.id,
i.id,
i.url
FROM company c
LEFT JOIN logo l
ON l.company_id = c.id
LEFT JOIN (SELECT pi.id,
pi.company_id
FROM product pi
WHERE (SELECT count(*)
FROM product pii
WHERE pii.company_id = pi.company_id
AND pii.id <= pi.id) <= 3) p
ON p.company_id = c.id
LEFT JOIN (SELECT i.id,
i.product_id,
i.path
FROM productimage ii
WHERE (SELECT count(*)
FROM productimage iii
WHERE iii.product_id = ii.product_id
AND iii.id <= ii.id) <= 1) i
ON i.product_id = p.id;
One subquery for productimage; replace the ? with the respective company ID:
SELECT c.id,
c.slug,
l.id,
l.path,
p.id,
i.id,
i.url
FROM company c
LEFT JOIN logo l
ON l.company_id = c.id
LEFT JOIN product p
ON p.company_id = c.id
LEFT JOIN (SELECT i.id,
i.product_id,
i.path
FROM productimage ii
WHERE (SELECT count(*)
FROM productimage iii
WHERE iii.product_id = ii.product_id
AND iii.id <= ii.id) <= 1) i
ON i.product_id = p.id
WHERE company_id = ?;
(Untested, as no DDL or DML was provided.)
I have a table with these data:
ID, Name, LastName, Date, Type
I have to query the table for the user with ID 1.
Get the row, if the Type of that user is not 2, then return that user, else return all users that have the same LastName and Date.
What would be the most efficient way to do this ?
What I had done is :
query1 = SELECT * FROM clients where ID = 1
query2 = SELECT * FROM client WHERE LastName = %s AND Date= %s
And I execute the first query
cursor.execute(sql)
rows = cursor.fetchall()
for row in rows:
if(row['Type'] ==2 )
cursor.execute(sql2(row['LastName'], row['Date']))
Save results
else
results = rows?
Is there a more efficient way of doing this using Joins?
Example if I only have a left join, how would I also ask if the type of the user is 2 ?
And if there is multiple rows to be returned, how to assign them to an array of objects in python?
Just do two queries to avoid loops here:
q1 = """
SELECT c.* FROM clients c where c.ID = 1
"""
q2 = """
SELECT b.* FROM clients b
JOIN (SELECT c.* FROM
clients c
c.ID = 1
AND
c.Type = 2) a
ON
a.LastName = b.LastName
AND
a.Date = b.Date
"""
Then you can just execute both queries and you'll have all the desired results you want without the need for loops since your loop will execute n number of queries where n is equal to the number of rows that match as opposed to grabbing it all in one join in one pass. Without more specifics as the desired data structure of final results, as it seems you only care about saving the results, this should give you what you want.
I want to do a SELECT statement that will get all the data in one table + follow all the foreign keys from that table with a LEFT OUTER JOIN. For example:
`orderitem`
id
name
title_id
`title`
id
name
In the above example, I would be able to use the statement:
SELECT * FROM orderitem LEFT OUTER JOIN title on orderitem.title_id=title.id
Is there a way that I could do this not knowing the table structure? That is, to have a function like the following:
def get_select_statement(table)
???
get_select_statement(orderitem)
==> "SELECT * FROM orderitem LEFT OUTER JOIN title on orderitem.title_id=title.id"
How would this be done?
To clarify this question, I think I'm looking for the following information from this function:
What are all the column names in the given table?
What tables do they reference in a ForeignKey relationship and what is the relationship to be able to join?
In addition, note that not all orderitems will have a title, so doing any sort of INNER JOIN would delete data.
In MySQLDB you could retrieve column names by using describe statement:
DESCRIBE table_name;
And all info about foreign keys:
select *
from information_schema.KEY_COLUMN_USAGE
where TABLE_SCHEMA = "schema_name"
and TABLE_NAME="table_name"
and REFERENCED_TABLE_NAME IS NOT NULL
To evaluate this query and load the result in python you could use SQLAlchemy package, for example.
engine = sqlalchemy.create_engine("mysqldb://user:password#host/db")
res = engine.execute("DESCRIBE table_name;")
columns = [row["Field"] for row in res]
res = engine.execute("{}".format(query_for_foreign_keys))
foreign_keys = [row["COLUMN_NAME"] for row in res]
referenced_column_names = [row["REFERENCED_COLUMN_NAME"] for row in res]
referenced_table_names = [row["REFERENCED_TABLE_NAME"] for row in res]
Then you could generate the query using all the data above