Hi guys I'm new with databases and I'm trying to make a query where I join 3 tables. I could make it and I want to clean up the result. I want to know how can I delete the column "pin" from users table and maybe some "ids" columns.
Select * from "wish-list"
Join products
On "wish-list".id = products.holiday_id
Join users
On "wish-list".user_id = users.id
Where "wish-list".id = 1
You need to specify which columns you really need in your output. At the moment you are using
SELECT * which outputs all columns of all joined tables.
Here is what it should look like:
SELECT holiday, products.description, users.pin FROM "wish-list"
JOIN products ON "wish-list".id = products.holiday_id
JOIN users ON "wish-list".user_id = users.id
WHERE "wish-list".id = 1
It's important that you reference all columns which are not your main entity (here wish-list) with tablename.column (products.description and not only description). It will work without referencing strictly but only if the column name is unique in your query.
Furthermore you can rename columns. This is useful for example if you want to get the id's of the product table and the wish-list table.
SELECT product.id AS product_id, id AS wishlist_id FROM "wish-list"
...
Hope that helps!
I currently have a schema set up in the following manner:
The table tblCategoryRiskArea is set up as an intermediate table for the many-to-many relationship that can exist between Categories and RiskAreas.
Within the tblBase table, I would like to make it so that the RiskArea choices are dependant upon the Category choice. MS Access allows you to set a Lookup for a field in a table based upon a Row Source SQL statement. I am having trouble figuring out the correct SQL statement to define the Row Source for RiskArea dependant upon Category. This:
SELECT tblRiskAreas.RiskAreaID, tblRiskAreas.RiskArea
FROM tblRiskAreas INNER JOIN
((tblCategories INNER JOIN tblBase
ON tblCategories.CategoryId = tblBase.Category)
INNER JOIN tblCategoryRiskArea
ON tblCategories.CategoryId = tblCategoryRiskArea.Category)
ON (tblRiskAreas.RiskAreaID = tblCategoryRiskArea.RiskArea)
AND (tblRiskAreas.RiskAreaID = tblBase.RiskArea)
WHERE (((tblCategoryRiskArea.Category)=[tblBase]![Category]))
ORDER BY tblRiskAreas.RiskAreaID;
is the best I've come up with so far, using MS Access' Query Builder, so all of the Inner Joins have been created just by my having defined the relationships between the tables and dragging them into the Query Builder. This query returns nothing, however.
I suspect that it may have something to do with the circular nature of the relationships I set up?
Thank you.
Edited: tblRiskArea contains 4 RiskAreas, as follows:
Environmental
Health
Safety
Security
Each Category can fall into one or two of these RiskAreas, so the tblCategoryRiskArea creates the relationship bewtween them.
First remove Category and RiskArea from tblBase and replace them for CategoriRiskAreaID
You will show in your form 2 combos. First combo Catagory data source:
Select CategoryId,Category from tblCategories
Second combo Risk Areas data source:
Select a.CategoryRiskId, b.RiskArea
from tblCategoryRiskArea a
inner join tblRiskArea b
where a.RiskAreaId=b.RiskAreaId
AND a.category = #ComboBoxCategorySelectedItem
Now you have the value to insert in tblBase, ComboBoxSelectedItem is tblCategoryRiskArea.CategoryRiskId
I've seen several questions about how to pull together multiple rows into a single comma-separated column with t-sql. I'm trying to map those examples to my own case in which I also need to bring columns from two tables together referencing a junction table. I can't make it work. Here's the query I have:
WITH usersCSV (userEmails, siteID)
AS (SELECT usersSites.siteID, STUFF(
(SELECT ', ' + users.email
FROM users
WHERE usersSites.userID = users.id
FOR XML PATH ('')
GROUP BY usersSites.userID
), 1, 2, '')
FROM usersSites
GROUP BY usersSites.siteID
)
SELECT * FROM usersCSV
The hard stuff here is based on this answer. I've added the WITH which, as I understand it, creates a sort of temporary table (I'm sure it's actually more complicated than that, but humor me.) to hold the values. Obviously, I don't need this just to select the values, but I'm going to be joining this with another table later. (The whole of what I need to do is still more complicated than what I'm trying to do here.)
So, I'm creating a temporary table named usersCSV with two columns which I'm filling by selecting the siteID column from my usersSites table (which is the junction table between users and sites) and selecting ', ' + users.email from my users table which should give me the email address preceded by a comma and space. Then, I chop the first two characters off that using STUFF and group the whole thing by usersSites.siteID.
This query gives me an error identifying line 5 as the problem area:
Column 'usersSites.userID' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
Why should this matter since the column in question is actually in the WHERE rather than the SELECT as is stated in the error? How can I fix it? I need only the users with an ID that matches an ID in the junction table. I've got tons of users that aren't mapped in that table and have no need to select them.
tl;dr- I need a temp table with distinct sites in one column and a comma-separated list of the email addresses of related users in the other. These two pieces of data come from other tables and will be put together using a junction table on the primary keys of those two tables. Hope that makes sense.
select distinct us.siteId,
STUFF((select ', ' + u.email
from users u
join usersSites us2 on us2.userId = u.userId
where us2.siteId = us.siteId
for xml path('')), 1, 2, '')
from usersSites us
SQL Fiddle
I have these two tables
I would like to know how to do to list the product table: ProdID, Quantity, Name, Price
and table productUser: userId, State
The problem is that I need to also list all the information of product table and adding the UserId field with the same value and the state looks for a default value would be false ..
It is possible? could also, not to add the userId, State and drive it from my application code for assigning values. thanks
UPDATE:
If I understand your question correctly, you want to list specific fields from both tables but only when the child records match your criteria. If so, the query below would allow you to specify the userID and State.
SELECT p.prodId
,p.Quantity
,p.Name
,p.Price
,pu.userId
,pu.State
FROM Product p
INNER JOIN ProductUser pu
ON p.prodId = pu.prodId
WHERE pu.userID = #userID
AND pu.State = 0
--AND pu.State = #State
If my understanding is not correct, please post some sample table data and indicate which results you want returned.
Update to your update: I've defaulted State to zero in the query above. Followup question: do you want columns from both tables or are you trying to do an existence check against ProductUser to return just columns from Product?
I'm having an SQL query (MSSQLSERVER) where I add columns to the resultset using subselects:
SELECT P.name,
(select count(*) from cars C where C.type = 'sports') AS sportscars,
(select count(*) from cars C where C.type = 'family') AS familycars,
(select count(*) from cars C where C.type = 'business') AS businesscars
FROM people P
WHERE P.id = 1;
The query above is just from a test setup that's a bit nonsense, but it serves well enough as example I think. The query I'm actually working on spans a number of complex tables which only distracts from the issue at hand.
In the example above, each record in the table "people" also has three additional columns: "wantsSportscar", "wantsFamilycar" and "wantsBusinesscar". Now what I want to do is only do the subselect of each additional column if the respective "wants....." field in the people table is set to "true". In other words, I only want to do the first subselect if P.wantsSportscar is set to true for that specific person. The second and third subselects should work in a similar manner.
So the way this query should work is that it shows the name of a specific person and the number of models available for the types of cars he wants to own. It might be worth noting that my final resultset will always only contain a single record, namely that of one specific user.
It's important that if a person is not interested in a certain type of cars, that the column for that type will not be included in the final resultset. An example to be sure this is clear:
If person A wants a sportscar and a familycar, the result would include the columns "name", "sportscars" and "familycars".
If person B wants a businesscar, the result would include the columns "name" and "businesscar".
I've been trying to use various combinations with IF, CASE and EXISTS statements, but so far I've not been able to get a syntactically correct solution. Does anyone know if this is even possible? Note that the query will be stored in a Stored Procedure.
In your case, there are 8 column layouts possible and to do this, you will need 8 separate queries (or build your query dynamically).
It's not possible to change the resultset layout within a single query.
Instead, you may design your query as follows:
SELECT P.name,
CASE WHEN wantssport = 1 THEN (select count(*) from cars C where C.type = 'sports') ELSE NULL END AS sportscars,
CASE WHEN wantsfamily = 1 THEN (select count(*) from cars C where C.type = 'family') ELSE NULL END AS familycars,
CASE WHEN wantsbusiness = 1 THEN (select count(*) from cars C where C.type = 'business') ELSE NULL END AS businesscars
FROM people P
WHERE P.id = 1
which will select NULL in appropriate column if a person doesn't want it, and parse these NULL's on client side.
Note that relational model answers the queries in terms of relations.
In your case, the relation is as follows: "this person needs are satisifed with this many sport cars, this many business cars and this many family cars".
Relational model always answers this specific question with a quaternary relation.
It doesn't omit any of the relation members: instead, it just sets them to NULL which is the SQL's way to show that the member of a relation is not defined, applicable or meaningful.
I'm mostly an Oracle guy but there's a high chance the same applies. Unless I've misunderstood, what you want is not possible at that level - you will always have a static number of columns. Your query can control if the column is empty but since in the outer-most part of the query you have specified X number of columns, you are guaranteed to get X columns in your resultset.
As I said, I am unfamiliar with MS SQL Server but I'm guessing there will be some way of executing dynamic SQL, in which case you should research that since it should allow you to build a more flexible query.
You may be able to do what you want by first selecting the values as separate rows into a temp table, then doing a PIVOT on that table (turning the rows into columns).
It's important that if a person is not
interested in a certain type of cars,
that the column for that type will not
be included in the final resultset. An
example to be sure this is clear:
You will not be able to do it in plain SQL. I suggest you just make this column NULL or ZERO.
If you want the query to be dynamically expand when new cars are added, then PIVOTing could help you somewhat.
There are three fundamentals you want to learn to make this work easy. The first is data normalization, the second is GROUP BY, and the third is PIVOT.
First, data normalization. Your design of the people table is not in first normal form. The columns "wantsports", "wantfamily", "wantbusiness" are really a repeating group, although they may not look like one. If you can modify the table design, you will find it advantageous to create a third table, lets call it "peoplewant", with two key columns, personid and cartype. I can go into detail about why this design will be more flexible and powerful if you like, but I'm going to skip that for now.
On to GROUP BY. This allows you to produce a result that summarizes each group in one row of the result.
SELECT
p.name,
c.type,
c.count(*) as carcount
FROM people p,
INNER JOIN peoplewant pw ON p.id = pw.personid
INNER JOIN cars c on pw.cartype = c.type
WHERE
p.id = 1
GROUP BY
p.name,
c.type
This (untested) query gives you the result you want, except that the result has a separate row for each car type the person wants.
Finally, PIVOT. The PIVOT tool in your DBMS allows you to turn this result into a form where there is just one row for the person, and there is a separate column for each of the cartypes wanted by that person. I haven't used PIVOT myself, so I'll let somebody else edit this response to provide an example using PIVOT.
If you use the same technique to retrieve data for multiple people in one sweep, keep in mind that a column will appear for each wanted type that any person wants, and zeroes will appear in the PIVOT result for persons who do not want a car type that is in the result columns.
Just came across this post through a google search, so I realize I'm late to this party by a bit, but .. sure this really is possible to do... however, I wouldn't suggest actually doing it this way because it's usually considered a Very Bad Thing (tm).
Dynamic SQL is your answer.
Before I say how to do it, I want to preface this with, Dynamic SQL is a very dangerous thing, if you aren't sanitizing your input from the application.
So, therefore, proceed with caution:
declare #sqlToExecute nvarchar(max);
declare #includeSportsCars bit;
declare #includeFamilyCars bit;
declare #includeBusinessCars bit;
set #includeBusinessCars = 1
set #includeFamilyCars = 1
set #includeSportsCars = 1
set #sqlToExecute = 'SELECT P.name '
if #includeSportsCars = 1
set #sqlToExecute = #sqlToExecute + '(select count(*) from cars C where C.type = ''sports'') AS sportscars, ';
if #includeFamilyCars = 1
set #sqlToExecute = #sqlToExecute + '(select count(*) from cars C where C.type = ''family'') AS familycars, ';
if #includeBusinessCars = 1
set #sqlToExecute = #sqlToExecute + '(select count(*) from cars C where C.type = ''business'') AS businesscars '
set #sqlToExecute = #sqlToExecute + ' FROM people P WHERE P.id = 1;';
exec(#sqlToExecute)