PostgreSQL query for tvshows with multiple genres - postgresql

I'm trying to create a database of tvshows that I have personally watched.
I have 3 tables:
tvshow_list: id, title, episodes, year
genres: id, genre name
genres_in_tvshows: genreid, tvshow id
I want to have a list which would show the tvshow id, title, episodes, and the genres. I cannot find a psql query that shows me how to 1. "group_concat" the genres so more than one shows and 2. join the tables

First your genres_in_tvshows table should have foreign keys referencing table tvshows and genres :
create table genres_in_tvshows
( genre_id integer, tvshow_id integer
, constraint pk primary key (genre_id, tvshow_id)
, constraint fk_tv foreign key (tvshow_id) references tvshow_list(id)
, constraint fk_ge foreign key (genre_id) references genres(id)) ;
Then you can use the following query :
SELECT tv.*, ge.*
FROM tvshow_list AS tv
INNER JOIN genres_in_tvshows AS gt
ON gt.tvshow_id = tv.id
INNER JOIN genres AS ge
ON ge.id = gt.genre_id

Related

Is primary key column included at the end of a secondary index

Given these tables
Foo
id (PK)
name
updated
Bar
foo_id (FK)
name
updated
And this query:
SELECT *
FROM Foo as f
JOIN Bar as b
ON f.id=b.foo_id
WHERE b.name = 'Baz' AND f.name = 'Baz'
ORDER BY f.updated ASC, f.id ASC
LIMIT 10
OFFSET 10
Are these appropriate indexes to add - in MySql InnoDB the primary key column is automatically added to the end of a secondary index. What is the case with Postgres?
CREATE INDEX foo_name_id_idx ON foo(name, id)
CREATE INDEX bar_name_id_idx ON bar(name, id)
PostgreSQL does not make the distinction between primary and secondary indexes, and the primary key index is no different from other indexes. So the primary key is not added to other indexes, and there is no point in doing that unless you have a special reason for it.
Depending on which of the conditions are selective, there are three possible strategies:
If the condition on bar.name is selective, use bar as the driving site:
CREATE INDEX ON bar (name);
-- foo.id is already indexed
If the condition on foo.name is selective:
CREATE INDEX ON foo (name);
CREATE INDEX ON bar(foo_id); -- for a nested loop join
If none of the conditions are selective:
/* here the "id" is actually at the end of the index,
but that is just because it appears in ORDER BY */
CREATE INDEX ON foo (name, updated, id); -- for the ORDER BY
CREATE INDEX ON bar (foo_id); -- for a nested loop join

SQLAlchemy Postgres upsert with partial index

I have a table called Person with three fields - ID, city and name. City can be null, so I have two partial unique indexes - one on ID and city where city is not null, and one on ID where city is null.
Now I want to have an upsert statement using SQLAlchemy, with those partial indexes, but I can't figure out the syntax. Currently I have:
table = models.Person.__table__
insert_statement = insert(table, upsert_values)
update_dict = {c.name: c for c in insert_statement.excluded if c.name != "id"}
upsert_statement = insert_statement.on_conflict_do_update(
index_elements=[table.c['id'], table.c['city']],
set_=update_dict
)
but when I try to execute I get
sqlalchemy.exc.ProgrammingError: (psycopg2.errors.InvalidColumnReference) there is no unique or exclusion constraint matching the ON CONFLICT specification
How can this work? Is there a way other than running pure SQL?

Why postgresql encount duplicate key when key not exists?

When I am inserting data into Postgresql(9.6),throw this error:
ERROR: duplicate key value violates unique constraint "book_intial_name_isbn_isbn10_key"
DETAIL: Key (name, isbn, isbn10)=(三銃士, , ) already exists.
SQL state: 23505
I add uniq constraint on columns name, isbn, isbn10.But when I check the distination table,it does not contains the record:
select * from public.book where name like '%三銃%';
How to fix?This is my insert sql:
insert into public.book
select *
from public.book_backup20190405 legacy
where legacy."name" not in
(
select name
from public.book
)
limit 1000
An educated guess, there may be more than one row in the source table book_backup20190405 which has the unique key tuple ('三銃', '', '').
Since the bulk INSERT INTO ... SELECT ... will be be transactional, you'll be none the wiser to the error, since all data will have been rolled back when the constraint fails.
You can verify this by running a dupe check on the source table:
SELECT name, isbn, isbn10, COUNT(*)
FROM public.book_backup20190405
WHERE name = '三銃'
GROUP BY name, isbn, isbn10
HAVING COUNT(*) > 1;
To see if there are duplicates.
Here's an example of how the source table can be the sole source of duplicates:
http://sqlfiddle.com/#!17/29ba3

I'm trying to insert tuples into a table A (from table B) if the primary key of the table B tuple doesn't exist in tuple A

Here is what I have so far:
INSERT INTO Tenants (LeaseStartDate, LeaseExpirationDate, Rent, LeaseTenantSSN, RentOverdue)
SELECT CURRENT_DATE, NULL, NewRentPayments.Rent, NewRentPayments.LeaseTenantSSN, FALSE from NewRentPayments
WHERE NOT EXISTS (SELECT * FROM Tenants, NewRentPayments WHERE NewRentPayments.HouseID = Tenants.HouseID AND
NewRentPayments.ApartmentNumber = Tenants.ApartmentNumber)
So, HouseID and ApartmentNumber together make up the primary key. If there is a tuple in table B (NewRentPayments) that doesn't exist in table A (Tenants) based on the primary key, then it needs to be inserted into Tenants.
The problem is, when I run my query, it doesn't insert anything (I know for a fact there should be 1 tuple inserted). I'm at a loss, because it looks like it should work.
Thanks.
Your subquery was not correlated - It was just a non-correlated join query.
As per description of your problem, you don't need this join.
Try this:
insert into Tenants (LeaseStartDate, LeaseExpirationDate, Rent, LeaseTenantSSN, RentOverdue)
select current_date, null, p.Rent, p.LeaseTenantSSN, FALSE
from NewRentPayments p
where not exists (
select *
from Tenants t
where p.HouseID = t.HouseID
and p.ApartmentNumber = t.ApartmentNumber
)

Import Data to a new table that has a nested table in it

INSERT INTO OrderNew (
SalesOrderID,
OrderDate,
DueDate,
ShipDate,
OnlineOrderFlag,
CustomerID,
CreditCardID,
SubTotal,
TaxAmt,
Freight,
TotalDue,
OrderInfo.salesorderdetail,
OrderInfo.orderqty ,
OrderInfo.productid,
OrderInfo.unitprice,
OrderInfo.unitpricediscount,
OrderInfo.linetotal
)
SELECT h."SalesOrderID" , h."OrderDate", h."DueDate", h."ShipDate", h."OnlineOrderFlag", h."CustomerID", h."CreditCardID", h."SubTotal", h."TaxAmt", h."Freight", h."TotalDue", d."SalesOrderDetailID", d."OrderQty", d."ProductID", d."UnitPrice", d."UnitPriceDiscount", d."LineTotal"
FROM "SalesOrderHeader" h
INNER JOIN "SalesOrderDetail" d ON d."SalesOrderID" = h."SalesOrderID"
WHERE d."SalesOrderID" = h."SalesOrderID" ;
This is the code I use in order to import data from some other tables.
However, I want the last column to be like a nested table.
These are the tables that I want to be one. So for one Sales Order ID from the table "SalesOrderHeader" there are a couple or more records with the same Sales Order ID on the table "SalesOrderDetail". So, how can I do it? Using a function?
I don't know if I am an understandable. But I can give more information.
You create two types in order to shrink a bit the new table which is going to be a combination of the SalesOrderHeader and SalesOrderDetail.
CREATE TYPE Shipping AS(OrderDate Date,DueDate Date,ShipDate Date);
CREATE TYPE ordersdetails AS (details text);
Then you create the table.
CREATE TABLE ordernew ( salesorderid serial NOT NULL, shippinginfo shipping, onlineorderflag integer, customerid serial NOT NULL, creditcardid integer, subtotal real, taxamt real, freight real, totaldue real, orderinfo ordersdetails[]);
As for the data, you will just copy the data from the other two tables but writing a right query in order not to create duplicate records. So, the code is below.
INSERT INTO OrderNew (
SalesOrderID,
OrderDate,
DueDate,
ShipDate,
OnlineOrderFlag,
CustomerID,CreditCardID,
SubTotal,
TaxAmt,
Freight,
TotalDue,
OrderInfo.salesorderdetail,
OrderInfo.orderqty ,
OrderInfo.productid,
OrderInfo.unitprice,
OrderInfo.unitpricediscount,
OrderInfo.linetotal
)
SELECT h."SalesOrderID" , h."OrderDate", h."DueDate", h."ShipDate", h."OnlineOrderFlag",
h."CustomerID", h."CreditCardID", h."SubTotal", h."TaxAmt", h."Freight", h."TotalDue",
d."SalesOrderDetailID", d."OrderQty", d."ProductID", d."UnitPrice", d."UnitPriceDiscount", d."LineTotal"
FROM "SalesOrderHeader" h
INNER JOIN "SalesOrderDetail" d ON d."SalesOrderID" = h."SalesOrderID"
WHERE d."SalesOrderID" = h."SalesOrderID" ;
To simply view the data that you recently inserted just run the following query:
SELECT orderinfo FROM ordernew;