Inner join - count and sum of field - sql

I have two tables editors and title_editors that I am trying to run an inner join query to show all editors and how many books they edit. I am not getting the desired result but a total sum of all books edited. How can list the name of all editors and how many books they edit and arrange the report so the editor editing the most books is listed first? SQLFIDDLE
Query
SELECT (e.first_name || ' ' || e.last_name) as Editor_Name, SUM(te.editor_order) as Books_Edited FROM editors e
INNER JOIN title_editors te ON te.editor_id = e.editor_id ORDER BY SUM(te.editor_order);
Table Schema
create table editors (editor_id char(11) not null, editor_lname varchar(40) not null, editor_fname varchar(20) not null, editor_positon varchar(12) null, phone char(12) null, address varchar(40) null, city varchar(20) null, state char(2) null, zip char(5) null, ed_boss char(11) null );
create table title_editors (editor_id char(11) not null, title_id char(6) not null, editor_order tinyint null);

In addition to the comment about CONCAT, you are missing your GROUP BY, and a DESC at the end of your ORDER BY to get them sorted the way you want.
SELECT
CONCAT(e.editor_fname,' ',e.editor_lname),
SUM(te.editor_order)
FROM
editors e
INNER JOIN
title_editors te
ON te.editor_id = e.editor_id
GROUP BY
e.editor_fname,
e.editor_lname
ORDER BY
SUM(te.editor_order) DESC;
http://sqlfiddle.com/#!9/47bd4/28

http://sqlfiddle.com/#!9/47bd4/22
Just GROUP your results.
SELECT (CONCAT(e.editor_fname,' ',e.editor_lname)) as Editor_Name
, SUM(te.editor_order) as Books_Edited
FROM editors e
INNER JOIN title_editors te
ON te.editor_id = e.editor_id
GROUP BY e.editor_fname,e.editor_lname
ORDER BY Books_Edited;

Related

Sort by column from another table

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()

How to SELECT titles by sales, where sales less than N?

I have 2 tables: titles and sales created by queries:
CREATE TABLE [dbo].[sales]
(
[stor_id] [char] (4) NOT NULL,
[ord_num] [varchar] (20) NOT NULL,
[ord_date] [datetime] NOT NULL,
[qty] [smallint] NOT NULL, --quantity of sold books in this transaction
[payterms] varchar(12) NOT NULL,
[title_id] varchar(6) NOT NULL, --FOREIGN KEY REFERENCES titles(title_id),
CONSTRAINT FK_S_title_id
FOREIGN KEY (title_id) REFERENCES titles(title_id),
CONSTRAINT PK_sales
PRIMARY KEY CLUSTERED (stor_id, ord_num, title_id)
) ON [PRIMARY]
CREATE TABLE [dbo].[titles]
(
[title_id] varchar(6) CONSTRAINT PK_titles PRIMARY KEY CLUSTERED,
[title] varchar(80) NOT NULL, --name of book
[type] char(12) NOT NULL DEFAULT ('UNDECIDED'),
[pub_id] char(4) NULL,
[price] money NULL,
[advance] money NULL,
[royalty] int NULL,
[ytd_sales] int NULL,
[notes] varchar(200) NULL,
[pubdate] datetime NOT NULL DEFAULT (getdate())
) ON [PRIMARY]
I know that I can get a table of pairs title and sumOfSales by this query
SELECT title, SUM(qty) AS sumOfSales
FROM titles AS t, sales AS s
WHERE t.title_id = s.title_id
GROUP BY title
ORDER BY title
It results as this:
But I need to select all titles that are sold less or equal than 10 times and get something like this, without qty (nor sumOfSales) column:
title
=======================================
ABookThatIsSoldLessOrEqual10Times
NameOfAnotherBookSoldLessOrEqual10times
NameOfBookSoldLessOrEqual10times
EDIT: Thank you for answers. I wanted to use HAVING, but it doesn't do what I need to have in result of SELECT. I need to have a list of just titles of books that are sold only 10 or less times.
I could use a temporary table and do 2 SELECTs instead of one. But it is not very good practice.
AS you need to show a list of just titles of books then try this:
SELECT title FROM titles AS t inner join sale AS s
on t.title_id = s.title_id
GROUP BY title
HAVING sum(qty) <= 10
ORDER BY title
Use HAVING clause:
SELECT title, SUM(qty) AS sumOfSales
FROM titles AS t, sales AS s
WHERE t.title_id = s.title_id
GROUP BY title
HAVING SUM(qty) < 11
ORDER BY title
You can write the condition as SUM(qty) <= 10 if you like, but I find SUM(qty) < 11 more elegant.
You need to add HAVING to your query
SELECT title, sum(qty) AS sumOfSales
FROM
titles AS t
INNER JOIN sales AS s ON t.title_id = s.title_id
GROUP BY title
HAVING sum(qty) <= 10
ORDER BY title

SQL Outer Join -- Join requires 3 tables

I'm using SQL Server query designer to try and form an outer query that will return the full name and address of each insured with home policies and those without policies. My create statements are the following:
CREATE TABLE Address (
AddressID integer NOT NULL,
HouseNumber Integer NOT NULL,
Street varchar(20) NOT NULL,
CityCounty varchar(20) NOT NULL,
StateAbb char(2),
CountryAbb char(2) NOT NULL,
Zip char(5) NOT NULL,
LastUpdatedBy varchar(20) NOT NULL,
LastUpdated date NOT NULL,
CONSTRAINT PK_Address PRIMARY KEY (AddressID));
CREATE TABLE Insured(
InsuredID integer NOT NULL,
FirstName varchar(15) NOT NULL,
LastName varchar(15) NOT NULL,
MI char(1),
DateOfBirth date NOT NULL,
CreditScore integer NOT NULL,
AddressID integer NOT NULL,
DriversLicenseNumber varchar(35),
LastUpdatedBy varchar(20) NOT NULL,
LastUpdated date NOT NULL,
CONSTRAINT PK_Insured PRIMARY KEY (InsuredID),
CONSTRAINT FK_InsuredAddress FOREIGN KEY (AddressID) references Address);
CREATE TABLE Policy(
PolicyID integer NOT NULL,
EffectiveDate date NOT NULL,
TerminationDate date NOT NULL,
Amount Numeric (8,2) NOT NULL,
PolicyYear integer NOT NULL,
PolicyType char(1) NOT NULL,
InsuredID integer NOT NULL,
AddressID integer NOT NULL,
LastUpdatedBy varchar(20) NOT NULL,
LastUpdated date NOT NULL,
CONSTRAINT PK_Policy PRIMARY KEY (PolicyID),
CONSTRAINT FK_PolicyAddress FOREIGN KEY (AddressID) references Address,
CONSTRAINT FK_PolicyInsured FOREIGN KEY (InsuredID) references Insured);
CREATE TABLE Home(
PolicyID integer NOT NULL,
ExteriorType varchar(30) NOT NULL,
Alarm char(3) NOT NULL,
DistanceToFireStation integer NOT NULL,
LastUpdatedBy varchar(20) NOT NULL,
LastUpdated date NOT NULL,
CONSTRAINT PK_Home PRIMARY KEY (PolicyID),
CONSTRAINT FK_HomePolicy FOREIGN KEY (PolicyID) references Policy);
CREATE TABLE Auto(
PolicyID integer NOT NULL,
VinNumber varchar(30) NOT NULL,
Make varchar(15) NOT NULL,
Model varchar(20) NOT NULL,
MilesPerYear integer NOT NULL,
LastUpdatedBy varchar(20) NOT NULL,
LastUpdated date NOT NULL,
CONSTRAINT PK_Auto PRIMARY KEY (PolicyID),
CONSTRAINT FK_AutoPolicy FOREIGN KEY (PolicyID) references Policy);
I believe that the query requires tables address, insured, policy and an outer right or left join but I cant get SQL server to recognize this as it keeps forming an inner join and cross join. What do I need for a query that returns insureds with home policies and their addresses and insureds with no policy and their addresses?
What I've tried so far:
SELECT Insured.InsuredID, Insured.FirstName,
Insured.LastName, Address.HouseNumber,
Policy.PolicyID
FROM Address RIGHT JOIN Policy
ON Address.AddressID = Policy.AddressID
RIGHT JOIN Insured ON Policy.AddressID = Insured.AddressID
ORDER BY Insured.InsuredID
This is the most recent query that returns what I need for insureds with a home policy but for the insureds without a policy I get nulls in the address.
SELECT i.InsuredID, i.FirstName, i.MI, i.LastName,
a.HouseNumber, a.Street, a.CityCounty, a.StateAbb, a.CountryAbb, a.Zip
FROM INSURED i
LEFT JOIN (SELECT * FROM Policy WHERE PolicyType = 'H') HomePolicy on
i.InsuredID = HomePolicy.InsuredID
LEFT JOIN Address a on HomePolicy.AddressID = a.AddressID;
Could you try this query:
SELECT i.InsuredID,
i.FirstName,
i.LastName,
a.HouseNumber,
p.PolicyID
FROM insured i
LEFT JOIN policy p ON i.AddressID = p.AddressID AND p.PolicyType = 'H'
LEFT JOIN address a ON i.AddressID = a.AddressID
ORDER BY i.InsuredID;
I think the joins were in the wrong order. Does this give you what you need?
Update: Joining the Insured table to the Address table will show you addresses regardless of if they have a policy or not.
Database design seem good.I think we have minor doubts regarding "PolicyType" column. what value it hold and what is the purpose of this column.
Say PolicyType='H' it mean that it is home policy . Or other way of finding same query is to check if that policyid exists in home table.
Is this correct ?
Main query,
What do I need for a query that returns insureds with home policies
and their addresses and insureds with no policy and their addresses?
Check this script,
--insureds with home policies and their addresses
select i.InsuredID,
i.FirstName,
i.LastName
A.HouseNumber
,1 INDICATE
from Insured i
INNER JOIN policy p ON i.InsuredID = p.InsuredID
INNER JOIN [Address] A ON A.ADDRESSID=I.ADDRESSID
WHERE EXISTS(SELECT PolicyID FROM Home H WHERE h.PolicyID=P.PolicyID)
AND NOT EXISTS(SELECT PolicyID FROM [Auto] a WHERE A.PolicyID=P.PolicyID)
UNION ALL
--insureds with no policy and their addresses
select i.InsuredID,
i.FirstName,
i.LastName
,A.HouseNumber
,0 INDICATE
from Insured i
INNER JOIN [Address] A ON A.ADDRESSID=I.ADDRESSID
WHERE EXISTS(SELECT InsuredID FROM policy p WHERE i.InsuredID = p.InsuredID )
I have use "EXISTS clause" because that table column is not require in your output.

SQL Server : Conditional Sort with Multiple Columns

I am having an issue with a conditional sort in SQL Server. I have a lengthy procedure that in the end produces a list of magazine subscriptions that are up for renewal. This is the basic structure of the end result table:
create table #renewals
(
product_no integer NULL,
quantity integer NULL,
order_date datetime NULL,
order_no integer NULL,
customer_no varchar(10) NULL,
description varchar(50) NULL,
first_name varchar(30) NULL,
middle_name varchar(30) NULL,
last_name varchar(30) NULL,
salute varchar(5) NULL,
acct_no char(8) NULL,
contact_type varchar(8) NULL,
contact_no integer NULL,
line_item int,
edition_code char(3) NULL
)
The issue lies in the multi-level sort that I am trying to accomplish. In the end, I need this data sorted by edition_code ASC which is simple enough.
However, some editions have add-on products which then need to be inserted underneath the correct edition_code. This is where I am running into a problem. An example of a regular edition code is 002 or 014. The add-on edition codes are 300, 302, etc. If I only sort by edition_code then all of the add-on editions get moved to the bottom of the list.
The following is a rundown of the result set:
product_no -- This is a different number than edition_code, but same principal
quantity -- self-explanatory
order_date -- self-explanatory
order_no -- For each unique result set, this number is the same
customer_no -- this is unique for each customer and helps to bundle main editions with their add-ons
description -- title of edition
first (through) last_name -- self-explanatory
salute -- self-explanatory
acct_no -- For each result set, this number is the same because all the customers will belong to the same account (think multiple doctors subscribing to a magazine but all work out of the same hospital)
contact_type -- PK
contact_no -- PK
line_item -- line number when entered on order (this does not help with sorting at all)
edition_code -- Unique code for an edition of our product
Below is the result I am expecting:
Customer_1 | Edition_1
Customer_2 | Edition_1
Customer_2 | Add-On_1
Customer_2 | Add-On_2
Customer_9 | Edition_1
Customer_6 | Edition_2
Customer_5 | Edition_2
Customer_5 | Add-On_2
Customer_3 | Edition_3
The closest I can get is by simply sorting by customer_no which will put the add-ons with their editions (You cannot order an add-on without ordering the main edition), but this does not sort by main edition code, which is what the overall (main) sort should accomplish.
This is the procedure that produces the result, not sure how it'll help:
CREATE TABLE #renewals
(
product_no integer NULL,
quantity integer NULL,
order_date datetime NULL,
order_no integer NULL,
customer_no varchar(10) NULL,
description varchar(50) NULL,
first_name varchar(30) NULL,
middle_name varchar(30) NULL,
last_name varchar(30) NULL,
salute varchar(5) NULL,
acct_no char(8) NULL,
contact_type varchar(8) NULL,
contact_no integer NULL,
line_item int,
edition_code char(3) NULL
)
INSERT INTO #renewals
(
product_no,
quantity,
order_date,
order_no,
customer_no,
description,
first_name,
middle_name,
last_name,
salute,
acct_no,
contact_type,
contact_no ,
line_item,
edition_code
)
SELECT
product.product_no,
order_table_1.quantity,
order_table_1.order_date,
order_table_1.order_no,
order_table_1.customer_no,
product.description,
isnull(customer_table_1.first_name, ''),
isnull(customer_table_1.middle_name, ''),
isnull(customer_table_1.last_name, ''),
isnull(customer_table_1.salute, ''),
order_table_1.acct_no,
'',
-1,
line_item_no,
order_table_1.edition_code
FROM order_table_1
LEFT OUTER JOIN product ON order_table_1.edition_code = product.edition_code
LEFT OUTER JOIN customer_table_1 ON order_table_1.customer_no = customer_table_1.customer_no AND order_table_1.acct_no = customer_table_1.acct
WHERE
(order_table_1.acct_no = #acct) AND
(order_table_1.school_year = #school_year) AND
(order_table_1.edition_code <> '065') AND
(order_table_1.status_code in ('E','A','F')) AND
(isnull(order_table_1.renewed,'N') <> 'Y')
UPDATE o
SET o.first_name = isnull(tc.first_name, ''),
o.middle_name = isnull(tc.middle_name, ''),
o.last_name = isnull(tc.last_name, ''),
o.salute = isnull(tc.salute, ''),
o.contact_type = tc.contact_type,
o.contact_no = tc.contact_no
FROM #renewals o, accounts ta, contacts tc
WHERE
(o.acct_no = ta.acct) AND
(ta.acct_type = tc.acct_type) AND
(ta.acct_no = tc.acct_no) AND
(o.customer_no = tc.customer_no) AND
(o.customer_no is not null) AND
(o.customer_no <> '') AND
(o.customer_no not like '999999999%')
SELECT
cast(o.product_no as int) as 'product_no',
o.quantity,
o.order_date,
o.order_no,
o.customer_no,
o.description,
o.first_name,
o.middle_name,
o.last_name,
o.salute,
o.acct_no,
o.contact_type,
o.contact_no,
o.line_item,
o.edition_code
FROM #renewals o
ORDER BY o.edition_code
You can't sort what you don't have. You need a table of edition_code, addon_code pairs. Then join to that table with
#renewals.edition_code in (X.edition_code, X.addon_code)
...
order by X.edition_code, X.addon_code
I'm making a few assumptions: that the two code sets don't overlap, that edition_code is always less than addon_code, and that you want the addons ordered by their code. Sometimes in cases like this a third column is required to express the sort order.

Need help with some Oracle SQL Queries

Here is the question posed by a professor: Find the minimum and maximum length of movies playing in each city.
And here is how I have my tables structured:
CREATE TABLE Theatres (
Name varchar2(50) not null,
City varchar2(50) not null,
State varchar2(50) not null,
Zip number not null,
Phone varchar2(50) not null,
PRIMARY KEY (Name)
);
CREATE TABLE Movies (
Title varchar2(100) not null,
Rating NUMBER not null,
Length NUMBER not null,
ReleaseDate date not null,
PRIMARY KEY (Title),
CHECK (Rating BETWEEN 0 AND 10),
CHECK (Length > 0),
CHECK (ReleaseDate > to_date('1/January/1900', 'DD/MONTH/YYYY'))
);
CREATE TABLE ShownAt (
TheatreName varchar2(50) not null,
MovieTitle varchar2(100) not null,
PRIMARY KEY (TheatreName, MovieTitle),
FOREIGN KEY (TheatreName) REFERENCES Theatres(Name),
FOREIGN KEY (MovieTitle) REFERENCES Movies(Title)
);
I've tried a few different queries, but keep getting issues. Here is what I have:
SELECT MIN(Movies.Length), MAX(Movies.Length), Theatres.Name
FROM Theatres, Movies, ShownAt
WHERE ShownAt.TheatreName = Theatres.Name AND
ShownAt.MovieTitle = Movies.Title AND
Theatres.City IN (SELECT UNIQUE City FROM Theatres);
Anybody see anything wrong? Thanks for the help!
You were pretty close I think. Just missing GROUP BY
SELECT
MIN(Movies.Length) AS Shortest,
MAX(Movies.Length) AS Longest,
Theatres.City
FROM Theatres
JOIN ShownAt ON ShownAt.TheatreName = Theatres.Name
JOIN Movies ON ShownAt.MovieTitle = Movies.Title
GROUP BY Theatres.City
I believe this would do the trick:
SELECT T.City, MIN(M.Length) AS MinLength, MAX(M.Length) AS MaxLength
FROM Movies AS M
JOIN ShownAt AS S ON S.MovieTitle = M.Title
JOIN Theatres AS T ON S.TheatreName = T.Name
GROUP BY T.City