Sort by column from another table - sql

I need a list over all Books in my db.
The list should contain:
Name of the Publisher , Book Title , year of publication for all books.
The list must be sorted alphabetically in order of publisher and then title.
I am not able to sort the list for BOTH condition, just for one.
Here the tables:
Publishers table
cursor.execute("DROP TABLE IF EXISTS `Publishers`;")
cursor.execute('''
CREATE TABLE `Publishers` (
`PublisherID` INTEGER PRIMARY KEY AUTOINCREMENT,
`Name` VARCHAR(45) NULL,
`City` TEXT NULL,
`Country` TEXT NULL
);
Books table
cursor.execute("DROP TABLE IF EXISTS `Books`;")
cursor.execute('''
CREATE TABLE `Books` (
`BookID` INTEGER PRIMARY KEY AUTOINCREMENT,
`Title` VARCHAR(45) NULL,
`ISBN` VARCHAR(45) NULL,
`ISBN13` TEXT NOT NULL CHECK (length(ISBN13)=13),
`PublisherID` INT NOT NULL,
`Year_Published` VARCHAR(45) NULL,
`Price` DOUBLE NULL,
FOREIGN KEY (`PublisherID`) REFERENCES Publishers(PublisherID) ON DELETE CASCADE ON UPDATE CASCADE
);
''')
I was able to write this but not to sort it for BOTH conditions
cursor = conn.cursor()
for row in cursor.execute('''SELECT Publishers.name,title,Year_Published
FROM books
INNER JOIN publishers on publishers.PublisherID = books.PublisherID
ORDER BY
title ASC, name.publisher ASC;'''):
print(row)
cursor.close()

You seem to be looking for a join:
select p.name, b.title, b.year_published
from books b
inner join publishers p on p.publisherID = b.publisherID
order by p.name, b.title

I had written a wrong conditions. Answer seems to be the following thanks to all!1
cursor = conn.cursor()
for row in cursor.execute('''SELECT Publishers.name,title,Year_Published
FROM books
INNER JOIN publishers on publishers.PublisherID = books.PublisherID
ORDER BY
publishers.name ASC, books.title ASC;'''):
print(row)
cursor.close()

Related

I need to JOIN using a linking table

The three tables are as follows:
CREATE TABLE Artist
(
ArtistKey char(20) NOT NULL PRIMARY KEY,
ArtistName varchar(50) NOT NULL
)
CREATE TABLE AlbumInfo
(
AlbumInfoKey char(20) NOT NULL PRIMARY KEY,
AlbumTitle varchar(50) NOT NULL,
AlbumDate date NULL,
AlbumStudio varchar(50) NULL
)
CREATE TABLE AlbumArtist
(
AlbumInfoKey char(20) NOT NULL,
ArtistKey char(20) NOT NULL,
PRIMARY KEY CLUSTERED
(
AlbumInfoKey ASC,
ArtistKey ASC
))
My objective is to list all of the artists and their albums. I can't seem to get anything to work.
I have tried:
SELECT
Artist.ArtistName,
AlbumInfo.AlbumTitle
FROM Artist
JOIN AlbumArtist
ON Artist.ArtistKey = AlbumArtist.ArtistKey
JOIN AlbumInfo
On AlbumInfo.AlbumInfoKey = AlbumArtist.AlbumInfoKey
However this gives me back nothing not even an error.
Alright, I had to re-do your whole task, and I have come up with more professional, and better way of managing database. You need to drop those tables, and re-do whole thing like show in code below :
--First create Artist table
CREATE TABLE Artist
(
Artist_key int PRIMARY KEY IDENTITY(1,1),
ArtistName varchar(50) NOT NULL,
);
--Then create Album table
CREATE TABLE AlbumInfo
(
Album_key int NOT NULL PRIMARY KEY IDENTITY(1,1),
AlbumTitle varchar(50) NOT NULL,
AlbumDate date NULL,
AlbumStudio varchar(50) NULL,
Artist_key int FOREIGN KEY (Artist_key) REFERENCES Artist(Artist_key)
);
-- Must have Artist data before referencing in the album table
INSERT into Artist (ArtistName) values ('John')
INSERT into AlbumInfo (AlbumTitle,AlbumDate,AlbumStudio,Artist_key) values ('ABC3','2020-6-12','Def3',(select Artist_key from Artist where Artist_key = 1 ))
--test if data has been inserted
SELECT * FROM Artist
SELECT * FROM AlbumInfo
-- And finally this query will show the Artist with their relevant Albums
SELECT ArtistName,af.AlbumTitle,AlbumStudio from Artist a join AlbumInfo af on af.Artist_key = a.Artist_key
And the result is :

Groupby Count Query On Two Tables Filtered by Condition on Third Table

I have three tables: Category, Mail and Classification. The relationship between the tables is outlined in this SQLFiddle with some sample data: http://sqlfiddle.com/#!9/118b24/3/0
CREATE TABLE `Category` (
`id` int(6) unsigned NOT NULL,
`name` varchar(20) NOT NULL,
PRIMARY KEY (`id`)
) DEFAULT CHARSET=utf8;
CREATE TABLE `Mail` (
`id` int(6) unsigned NOT NULL,
`content` varchar(500) NOT NULL,
`date` datetime NOT NULL,
PRIMARY KEY (`id`)
) DEFAULT CHARSET=utf8;
CREATE TABLE `Classification` (
`id` int(6) unsigned NOT NULL,
`mail_id` int(6) unsigned NOT NULL,
`category_id` int(6) unsigned NOT NULL,
FOREIGN KEY (mail_id) REFERENCES Mail(id),
FOREIGN KEY (category_id) REFERENCES Category(id),
PRIMARY KEY (`id`)
) DEFAULT CHARSET=utf8;
I first run a query to get the count of emails assigned to each category:
SELECT Category.name, count(Classification.category_id) FROM Category LEFT OUTER JOIN Classification ON Classification.category_id = Category.id GROUP BY Category.name
Which works fine.
But I would now like to add a filter based on the date that is in the Email collection. If I had a join with a filter collection:
SELECT Category.name, count(Classification.category_id) FROM Category JOIN Mail ON Mail.date < '2019-03-24' LEFT OUTER JOIN Classification ON Classification.category_id = Category.id GROUP BY Category.name
But now the count only doubles and it seems the filter isn't even applied. Why isn't the filter working and what should I do to fix it?
You need a JOIN condition between Classification and Mail:
SELECT ca.name, count(cl.category_id)
FROM Category LEFT JOIN
Classification cl
ON cl.category_id = c.id LEFT JOIN
Mail m
ON m.id = cl.mail_id AND -- your JOIN key goes here
m.date < '2019-03-24'
GROUP BY c.name ;

How to get the highest appearance value in one table, from another table?

So I have 3 tables referencing cars, assurance and accident.
I want to know the brand of vehicles who had the most accidents, compared to others.
I have tried a lot of ways to that, but mostly i only get or all the brands returned or the brand of the car that was registered the most, not the one that had most accidents
These are my tables
create table car(
n_veic bigint not null,
matric varchar(15) not null,
pais_matric text not null,
n_pess bigint not null,
tipo text not null,
cor text not null,
brand text not null,
modelo varchar(15),
primary key(n_veic),
unique(matric),
foreign key (n_pess) references pessoa(n_pess)
);
create table ensurance(
apolice bigint not null,
segurado bigint not null,
car bigint not null,
datai date not null,
dataf date not null,
cobertura numeric(10,2) not null,
primary key(apolice),
unique(segurado, veiculo),
foreign key (segurado) references pessoa(n_pess),
foreign key (car) references car(n_veic)
);
create table accident(
n_acid bigint not null,
pess_segura bigint not null,
veic_seguro bigint not null,
data date not null,
local varchar(255) not null,
descr text not null,
primary key(n_acid),
unique(n_acid, veic_seguro),
foreign key (pess_segura,veic_seguro) references ensurance(segurado, car)
This is what i tried
SELECT marca
FROM veiculo NATURAL JOIN acidente
GROUP BY marca
HAVING count (distinct n_veic)>=ALL
(SELECT count (distinct n_veic)
FROM veiculo NATURAL JOIN acidente
GROUP BY marca);
I think the logic is:
select c.marca, count(*) as num_acidentes
from acidente a join
car c
on a.veic_seguro = c.n_veic
group by c.marca
order by num_acidentes desc;
You can use fetch first 1 row only -- or whatever is appropriate for your database -- to get only one row.
Try this-
Note:
1. Try to avoid NATURAL JOIN and use specific column reference.
2. Rethink DISTINCT for count is really necessary or not.
SELECT TOP 1 marca, COUNT(DISTINCT n_veic)
FROM veiculo
NATURAL JOIN acidente
GROUP BY marca
ORDER BY COUNT(DISTINCT n_veic) DESC

how to create a query two or more values?

I would need if I could help with the following code:
CREATE TABLE `car` (
`car_id` int(10) unsigned NOT NULL auto_increment,
`car_name` varchar(25) NOT NULL,
`car_year` date NOT NULL,
PRIMARY KEY (`user_id`)
) ENGINE=InnoDB;
CREATE TABLE `people` (
`peo_id` int(10) unsigned NOT NULL auto_increment,
`peo_name` varchar(50) NOT NULL,
`peo_surname` varchar(200) NOT NULL,
`car_id` int(10) unsigned NOT NULL,
PRIMARY KEY (`fav_id`),
KEY `FK_Favorites` (`user_id`),
CONSTRAINT `FK_Favorites` FOREIGN KEY (`car_id`) REFERENCES `car` (`car_id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB;
I have questions, show all cars that are more than 3 people ordered by year of car.
Thank you very much, sorry for my bad English
SELECT
c.car_id
,c.car_year
,COUNT(p.peo_id)
FROM car c
INNER JOIN people p on c.card_id = p.car_id
GROUP BY c.car_id ,c.car_year
HAVING COUNT(p.peo_id) > 3
ORDER BY c.car_year
First, find number of cars with more than three people
select car_id
from people
group by car_id
having count(*) > 3
Now, get the car details
select * from car
where car_id in
(
select car_id
from people
group by car_id
having count(*) > 3
)
order by car_year

Help with SELECT statement

I have two tables: players and cards2
In each cards2 row, there is at least one player id (pid, pid2, pid3, pid4). I'm trying to come up with a select statement to get all fname's and lname's if there is more than one player id (pid's that are not 0). There is always a pid, but not always a pid2, pid3, etc. Does this make sense?
Here are the structures.
Players table
CREATE TABLE IF NOT EXISTS `players` (
`player_id` mediumint(10) NOT NULL AUTO_INCREMENT,
`sport_id` tinyint(4) NOT NULL,
`fname` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
`lname` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
`hof` tinyint(4) NOT NULL,
PRIMARY KEY (`player_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=421 ;
Cards2 table
CREATE TABLE IF NOT EXISTS `cards2` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`pid` mediumint(10) NOT NULL,
`pid2` mediumint(10) NOT NULL,
`pid3` mediumint(10) NOT NULL,
`pid4` mediumint(10) NOT NULL,
`num` smallint(4) NOT NULL DEFAULT '0',
`year` year(4) NOT NULL DEFAULT '0000',
`notes` text,
`new_manuf` varchar(50) NOT NULL,
`sportid` tinyint(4) NOT NULL DEFAULT '0',
`fname` varchar(25) NOT NULL,
`lname` varchar(100) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=572 ;
Thanks in advance!
You could do it like this:
SELECT
id,
P1.fname AS fname1,
P1.lname AS lname1,
P2.fname AS fname2,
P2.lname AS lname2,
P3.fname AS fname3,
P3.lname AS lname3,
P4.fname AS fname4,
P4.lname AS lname4
FROM cards2
LEFT JOIN players P1 ON pid = P1.player_id
LEFT JOIN players P2 ON pid2 = P2.player_id
LEFT JOIN players P3 ON pid3 = P3.player_id
LEFT JOIN players P4 ON pid4 = P4.player_id
You might want to consider if it is a good idea to normalize your database though. Having four columns for four players seems like a bad idea. What if you later want to allow 6 players?
You might want to consider redesigning your tables if that's a possibility. The repeating player ID's in the CARD2 table will make querying difficult and artificially limit how many players can be associated with a particular card. If you're still in the design stage you can save yourself some grief later by redoing things now. Here's a quick shot at it:
First, redo the 'cards2' table to eliminate the player references:
CREATE TABLE IF NOT EXISTS `cards2` (
`card_id` int(11) NOT NULL AUTO_INCREMENT,
`num` smallint(4) NOT NULL DEFAULT '0',
`year` year(4) NOT NULL DEFAULT '0000',
`notes` text,
`new_manuf` varchar(50) NOT NULL,
`sportid` tinyint(4) NOT NULL DEFAULT '0',
PRIMARY KEY (`card_id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=572;
Then create what's called a "junction table" to map the many-to-many relationship between cards and players (i.e. one player can appear on many cards, and many players can appear on one card):
CREATE TABLE IF NOT EXISTS 'card_player' (
'card_id' int(11) NOT NULL,
'player_id' mediumint(10) NOT NULL,
PRIMARY KEY ('card_id', 'player_id'),
FOREIGN KEY 'card_id' REFERENCES card2.card_id,
FOREIGN KEY player_id REFERENCES players.player_id
) ENGINE=MYISAM DEFAULT CHARSET=latin1;
Eliminating the repeated player_id's in the CARDS2 table should make querying easier. For example,
SELECT c.card_id, p.fname, p.lname
FROM players p,
cards2 c,
card_player x
WHERE x.card_id = c.card_id AND
p.player_id = x.player_id
ORDER BY c.card_id;
This also eliminates the limitation of having at most four players associated with a particular card, so if you have a team card with 20 players on it this new set of table definitions can handle it.
I hope this helps.
Use:
SELECT CONCAT(p1.fname, ' ', p1.lname) AS player1,
CONCAT(p2.fname, ' ', p2.lname) AS player2,
CONCAT(p3.fname, ' ', p3.lname) AS player3,
CONCAT(p4.fname, ' ', p4.lname) AS player4,
FROM CARDS2 c
JOIN PLAYERS p1 ON p1.playerid = c.pid
LEFT JOIN PLAYERS p2 ON p2.playerid = c.pid2
LEFT JOIN PLAYERS p3 ON p3.playerid = c.pid3
LEFT JOIN PLAYERS p4 ON p4.playerid = c.pid4
About making sense, wouldn't it be cleaner creating simple n:m players_tables_map table? http://en.wikipedia.org/wiki/First_normal_form