Filling in a database - sql

Let's say we have a database with the following two tables: books and authors.
The authors table has columns: id, name.
The books table has columns: id, title, author_id (refers to the authors table).
I add new books into the database manually, but I'd like to write a simple sql script to automate this task. Can I avoid looking up author_id by author name in the authors table (can this step be done by a database)? What I want is to enter the book title and the author name (i.e. I don't want to do looking up author_id first), something like this:
//script.sql
INSERT "A quick guide to SQL", "Philip Collins"

You can use a SELECT statement together with an insert:
insert into books (title, author_id)
select 'A quick guide to SQL', a.id
from author a
where a.name = 'Philip Collins';
This assumes that the author name is unique, otherwise it will insert multiple rows into the books table.
Note that in SQL, string constants are enclosed in single quotes ('), double quotes (") are for identifiers.

You can create a view:
create view v_books as
select b.*, a.name
from books b join
authors a
on b.author_id = a.id;
This is a stored query and can be used like a table.

Related

Updating a table in oracle from another table with duplicate records present

I have two tables, lets say table books and table authors.
Table books has 4 fields, BookId, Title, Author, Publisher
Table authors has 5 field AuthorID, Title, Author, Publisher, Price
I want to update book to have the price field from authors. There is no one unique key so the criteria is if Title or Author or Publisher match then add that price to books. In my case authors has many duplicate values in Title, Author or Publisher so I get update errors because of duplicates. So basically how in oracle can I update books with that criteria and in case of duplicates just choose any record, it doesn't matter which and put it in there? Other languages have the top command that you can use to do such a thing but it looks like Oracle lack that.
I have tried various merge and update statements on my own with no luck. Something like:
UPDATE books n
set n.price = (
select t.price from authors t where
n.title= t.title or
n.author = t.author or
n.publisher = t.publisher)
But that statement isn't checking for duplicates and stopping them thus failing so I am missing that key.
The simple way is:
UPDATE books n
set n.price = (
select t.price from authors t where
( n.title= t.title or
n.author = t.author or
n.publisher = t.publisher )
and rownum = 1)

Counting positions in a row oracle

I'm making bookstore database and in the table "Authors" I've got column where i'd like to count books written by author in the table "Books". Table "Books" has foreign key "id_author". I have no idea how to do it, it's something like
SELECT COUNT(*) FROM Books WHERE id_author = "id of chosen author"
What to write in code in place of "id of chosen author"?
How to put it in a row in table "Author"?
You could join on the authors table and query by its columns (e.g., the first and last name):
SELECT COUNT(*)
FROM books b
JOIN author a ON b.id_author = a.id
WHERE a.firstname = 'John' AND a.lastname = 'Doe'
Depending on the application you have, the application might already have the author id. This means that you could just do a
SELECT COUNT(*) FROM Books WHERE id_author = "id of author provided by application"
Although the difference is probably not large compared to Mureinik's answer, this can enhance your performance on large databases as you do not have to do the join between author and book table.
Number of books by author:
select a.author, count(1)
from author a
join books b
on a.id = b.id_author
group by a.author

SQL: Querying Against Composite Entity

I'm trying to figure out how to query against a composite key.
In my select result, I want the book name, author, category, and selling price. So far I have select title,category,price from books1 where books1.category='MYS';
but I'm not sure how to go about getting the author name.
I'm not sure why you have books1 when the model show the table named books. Books is a horrible name for a table -- typically in relational databases you use the singular -- eg book.
Here is how you do a join:
Select a.First, a.Last
from books b
join books_authors ab on b.b_code = ab.book_code
join authors a on ab.authorId = a.id
where b.category = 'MYS'
also all of your field names have spaces in them -- I don't know what platform you are using so I've no idea how to escape the names. Using spaces in field name is non-standard and not acually SQL. I'd advise against it whenever possible.

SQL multiplicity many to many insertion process

my question it seems to be pretty simple but unfortunately i couldn't find any satisfactory answer for this.
Please take a look on the following example:
Table Author define a author, Document has at least one author and table Authors group all authors that a document has.
My question is: Each time that i insert a document i need to verify if my group of authors exists already on table Authors.
What is the best way to do this?
I suppose that in first place i will need to verify if this group already exist and then, i should get that id (if already exist) or generate a new record on Authors (if group doesn't exist).
Question:
Is this the correct logic process that should occur on tables that has a multiplicity of many to many?
How can i check if a group of values already exist on table Authors??
There is something like this select * from Authors where a_id IN(1,2,3) but in a exclusive way. :S
Any help would be great.
Thanks
I would rather go with a solution with three tables:
Author
Document
rel_author_document
And rel_author_document will have a structure like:
author_fk
document_fk
You don't need to add a new group, but just to associate authors to a document.
In rel_author_document you can even add additional columns like role, if you need something like that.
With this approach you can have two documents with the same group of authors, but this won't kill you performances.
In case your question is for a homework assignment and you can't change table structure then:
Query the Authors table to see if you have a group of Author with the same number of author_id in the where condition, something like:
select count(1) cnt
from Authors
where a_id IN(1,2,3)
If cnt is different from the number of author_ids, then insert a new group
If cnt is equal then get the id of that group of Authors:
select ID
from Authors
where a_id = 1
or a_id = 2
or a_id = 3
group by 1
having count(1) = 3
If its a "many-to-many" relationship I believe the table structure you are looking for is:
Author (
a_id,
name,
birth_date,
domain)
Document (
d_id,
abstract,
year)
Auth_Doc (
a_id,
d_id
)
In terms of checking if there is already a group of authors, it depends n how you're displaying your data. If I was uploading a document and I wanted to check if a set of authors exist, I would do the following:
Say your data is stored as:
a_id | name
1 | john, jack, bob
SELECT * FROM Author WHERE name like '%john%'
I hope this helps,
Sohail

Selecting only authors who have articles?

I've got two SQL Server tables authors, and articles where authors primary key (AuthorID) is a foreign key in the articles table to represent a simple one-to-many relationship between authors and articles table. Now here's the problem, I need to issue a full text search on the authors table based on the first name, last name, and biography columns. The full text search is working awesome and ranking and all. Now I need to add one more criteria to my search, I need all the non-articles contributors to be ignored from the search. To achieve that I chose to create a view with all the contributors that have articles and search against this view. So I created the view this way:
Create View vw_Contributors_With_Articles
AS
Select * from Authors
Where Authors.ContributorID
IN ( Select Distinct (Articles.ContributorId) From Articles)
It's working but I really don't like the subquery thing. The join gets me all the redundant authorIDs, tried distinct but didn't work with the biography column as it's type is ntext. Group by wouldn't do it for me because I need all the columns not any aggregate of them.
What do you think guys? How can I improve this?
An EXISTS allows for the potential duplicate entries when there are multiple articles per author:
Select * from Authors
Where EXISTS (SELECT *
FROM Articles
WHERE Articles.ContributorId = Authors.ContributorId)
Edit:
To clarify, you can not DISTINCT on ntext columns. So, you can not have a JOIN solution, unless you use a derived table on articles in the JOIN and avoid using articles directly. Or you convert the ntext to nvarchar(max).
EXISTS or IN is your only option.
Edit 2:
...unless you really want to use a JOIN and you have SQL Server 2005 or higher, you can CAST and DISTINCT (aggregate) to avoid multiple rows in the output...
select DISTINCT
Authors.ContributorID,
Authors.AnotherColumn,
CAST(Authors.biography AS nvarchar(max)) AS biography,
Authors.YetAnotherColumn,
...
from
Authors
inner join
Articles on
Articles.ContributorID = Authors.ContributorID
You want an inner join
select
*
from
Authors
inner join
Articles on
Articles.ContributorID = Authors.ContributorID
This will return only authors who have a an entry on the Articles table, matched by ContributorID.
Select the distinct contributorIDs from the Articles table to get the individual authors who have written an article, and join the Authors table to that query - so something like
select distinct Articles.contributorID, Authors.*
from Articles
join Authors on Articles.contributerID = Authors.ContributerId