SQL: Querying Against Composite Entity - sql

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.

Related

SQL Query multiple tables same values

I'm having an issue creating a query. Here are the specifics.
There are 2 tables company_career and company_people.
People contains person information (Name, Address, etc) and Career contains historical career information (job_title, department, etc.)
People is linked to Career by job_ref_id.
Direct_Report_id lies in the career table and contains a unique id that correlates to job_ref_id.
Example: job_ref_id = '1' results in direct_report_id ='A'. I then use the value produced from direct-report_id (i.e., 'A') and query the job_ref_id = 'A' and this produces the employee name. Since it produces the employee name (which is actually the manager) I need to know how I would query this to present this as the manager name.
I think I know what you are looking for, you just need to use joins and aliases. For example:
SELECT
cp.name AS [EmployeeName],
cp.address AS [EmployeeAddress],
cc.job_title AS [EmployeeTitle],
cc.department AS [EmployeeDept],
m.name AS [ManagerName]
FROM company_people cp
LEFT JOIN company_career cc ON cc.job_ref_id = cp.job_ref_id
LEFT JOIN company_people m ON m.job_ref_id = cc.direct_report_id

How should I JOIN my tables?

I'm learning C# and some SQL server, and now i am trying to get information from my small database.
I have two tables: Movie and MovieHandler.
In the table Movie, i have MovieCodeLable, which is a uniqe number, and the Title of the movie.
In the MovieHandler table, i have MovieCodeLable which is the same as in my Movie table, and i have also her the colum InStore, which is eighter 0 or 1 for not in store or in store.
I'm trying to display the Title for the movies which is not in the store. But i find it hard figure out how to join tables.
I have tried this SQL query:
SELECT Title
FROM Movie
JOIN MovieCodeLable
ON MovieHandler.MovieCodeLable
WHERE InStore = 0
Since i only get errors trying this query in Visual Studio 2012, i've probably missed something fundametal with SQL and JOINS, but i hope that someonw could make JOINS smooth as butter for me and others, struggeling to learn it.
Your JOIN is wrong and your ON clause is incomplete. The JOIN should involve the names of the 2 tables that you are joining, which in this case is Movie and MovieHandler The ON should be expression of format A = B. So your query should be:
SELECT Title
FROM Movie
JOIN MovieHandler
ON Movie.MovieCodeLable = MovieHandler.MovieCodeLable
WHERE InStore = 0
You need to specify both JOIN fields
SELECT Title
FROM Movie
JOIN MovieHandler
ON Movie.MovieCodeLable = MovieHandler.MovieCodeLable
WHERE InStore = 0
You have to do the query like this
SELECT Title
FROM Movie
JOIN MovieHandler
ON Movie.MovieCodeLable = MovieHandler.MovieCodeLable
WHERE InStore = 0
You had to complete the ON condition.You need to specify the columns to match after ON condition.Go to this link there is explanations with tables http://www.w3schools.com/sql/sql_join.asp
I do it this way in oracle. Not sure if it will work for you...
Try:
Select Mv.Title
,other_columns
from Movie Mv
,MovieHandler Mvh
Where Mv.MovieCodeLable = Mvh.MovieCodeLable
and (whatever other criteria you want
As long as MovieCodeLable is unique you're ok
Other_columns can be any column of either table format with table.column syntax (I use table shortcuts Mv and Mvh to reference the tables, I don't know if this is legal for non-oracle)

SQL WHERE <from another table>

Say you have these tables:
PHARMACY(**___id_pharmacy___**, name, addr, tel)
PHARMACIST(**___Insurance_number___**, name, surname, qualification, **id_pharmacy**)
SELLS(**___id_pharmacy___**, **___name___**, price)
DRUG(**___Name___**, chem_formula, **id_druggistshop**)
DRUGGISTSHOP(**___id_druggistshop___**, name, address)
I think this will be more specific.
So, I'm trying to construct an SQL statement, in which I will fetch the data from id_pharmacy and name FROM PHARMACY, the insurance_number, name, and surname columns from PHARMACIST, for all the pharmacies that sell the drug called Kronol.
And that's basically it. I know I'm missing the relationships in the code I wrote previously.
Note: Those column names which have underscores left and right to them are underlined(Primary keys).
The query you've written won't work in any DBMS that I know of.
You'll most likely want to use some combination of JOINs.
Since the exact schema isn't provided, consider this pseudo code, but hopefully it will get you on the right track.
SELECT PH.Ph_Number, PH.Name, PHCL.Ins_Number, PHCL.Name, PHCL.Surname
FROM PH
INNER JOIN PHCL ON PHCL.PH_Number = PH.Ph_Number
INNER JOIN MLIST ON MLIST.PH_Number = PH.PH_Number
WHERE MLIST.Name = "Andy"
I've obviously assumed some relationships between tables that may or may not exist, but hopefully this will be pretty close. The UNION operator won't work because you're selecting different columns and a different number of columns from the various tables. This is the wrong approach all together for what you're trying to do. It's also worth mentioning that a LEFT JOIN may or may not be a better option for you, depending on the exact requirements you're trying to meet.
Ok, try this query:
SELECT A.id_pharmacy, A.name AS PharmacyName, B.Insurance_number,
B.name AS PharmacistName, B.surname AS PharmacistSurname
FROM PHARMACY A
LEFT JOIN PHARMACIST B
ON A.id_pharmacy = B.id_pharmacy
WHERE A.id_pharmacy IN (SELECT id_pharmacy FROM SELLS WHERE name = 'Kronol')

How can we build such an extremely complex SQL statement?

[Book] isbn(PK),title,category_id,subcategory_id,price
[Author] isbn(FK),author_id(PK),name
[Category] category_id(PK),name
[SubCategory] sub_category_id(PK),category_id(FK),name
I have a database (not designed by me) that contains the above four tables.
I want to have a book list having the following format:
isbn, title, author name(s), category name, subcategory name(may not have), price
But there's some complexity, as you can see, each book can have more than one author, the author name column should have author names separated by commas.
And for the category which is the more difficult part, there are some categories that have no subcategories and thus, some book records have subcategory_id set to 0 because its category_id refers to an category that has no subcategories, in this case, the subcategory name column in the book list does not need to show anything.
I really have no idea how such a complex a complex SQL statement can be built quickly to get the book list. Would somebody kindly think of a solution?
Many thanks to you all.
When you find yourself building an "extremely complex SQL statement", it's usually best to step back and rethink.
Remember this - the vast majority of operations performed on database table are selects, not inserts or updates (though there are exceptions to every rule, of course).
The right time to be "spending" CPU cycles calculating things like author lists is when the list changes, not when you just want to extract the information.
Add another column to the book table called author_list and then create an insert/update trigger on authors so that this column is rebuilt whenever an author is changed for the specific ISBN.
That puts the cost where it should be and will make your query a lot simpler. The trigger ensures the data stays consistent, and it's okay to break 3NF if you know what you're doing.
As to the subcategory, the case statement can be your friend, but per-row functions on select never scale well.
I would just create a set of rows in subcategories with the id of 0 (one for each category) and make its name blank. Then it can be done with a simple join without having to concern yourself with performance. This could also be don with a trigger on category so every category will always have a subcategory of 0.
With those two changes, the query becomes a lot less complex, something along the lines of:
select b.isbn, b.title, b.author_list, c.name, sc.name, b.price
from Book b, Category c, SubCategory sc
where b.category_id = c.category_id
and b.category_id = sc.category_id
and b.subcategory_id = sc.subcategory_id
order by ...
This query should scream along since it's using just the basic levels of relational algebra (i.e., no per-row functions (including case statements), no subqueries). And that's an "old-school" query, you may get even more performance by using explicit rather than implicit JOINs.
One final point: a properly 3NF schema would not have the ISBN in the authors table - a better option would be to have a separate BookAuthor table holding the ISBN and author_id to properly model the many-to-many relationship. But you may have aleready changed that for performance (I don't know).
That's an odd schema, not how I would have designed it. Being denormalized, it's probably going to have a lot of duplication in the author table.
Anyways, because you may have one or more authors, joins aren't really going to cut it for that information. Some things, to be honest, are better done outside of SQL and this is one of them. You can just build a loop that constructs the information and emits the data when the ISBN changes, assuming you do your ordering well.
As for the categories and subcategories, use a left join and it will return NULL on the subcategory information which you can test for. If there's more than one subcategory possible for the book (or categories for that matter), then you're really DOA with SQL here.
See #Pax's answer for a nicer way to handle the null / zero values for sub_category_id
select isbn, a.name as author_name, c.name as category_name, sc.name as subcategory_name, price
from Book
join Author a on isbn = a.isbn
join Category c on category_id = c.category_id
join SubCategory sc on category_id = sc.category_id and subcategory_id = sc.subcategory_id
where subcategory_id != 0
union
select isbn, a.name as author_name, c.name as category_name, '' as subcategory_name, price
from Book
join Author a on isbn = a.isbn
join Category c on category_id = c.category_id
join SubCategory sc on category_id = sc.category_id and subcategory_id = sc.subcategory_id
where subcategory_id = 0
Well, the subcategory business is poor database design. Even if you assume that a book can only be in one category, it's a poor design because (in that case), a category can always bee derived from the subcategory, so you've introduced redundancy by having book have attributes for both.
As far as the query you want, that's just a matter of doing the joins and projecting teh select statement. In you don't know enough SQL to do that, you probably shouldn't be trying to write queries (or you should be asking about basic joins and projections).
As to how you turn multiple rows into one (which is what you want to do with the authors), that depends on your RDBMS (which you don't specify) and/or your front-end.
Something like this should be close.
select
Book.ISBN,
Book.Title,
Author.Name,
Category.Name as Category_Name,
SubCategory.Name as SubCategory_Name,
Book.Price
from
Book join Author
on Book.ISBN = Author.ISBN
join Category
on Book.Category_ID = Category.Category_ID
join SubCategory
on Book.Category_ID = SubCategory.Category_ID
and Book.SubCategory_ID = SubCategory.Sub_Category_ID

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