SQL Server SELECT composite table - sql-server

I have the below query:
SELECT p.id as prod_id, * FROM products AS p
LEFT JOIN Product_UPC AS UPC ON UPC.ProductID = p.id
LEFT JOIN Brands AS b ON p.brand = b.id
LEFT JOIN productCategoryLink AS c ON c.ProductID = p.id
WHERE (p.id = '$this->prod_id')
A product can be assigned to multiple categories and therefore I have a composite table consisting of product and category IDs. I want to amend the above query so that it only brings out one row of data as at the moment it bring out multiple depending on how many categories there are in the composite table. I would like to somehow have the rows of category IDs brought out and added to the one row.
eg.
id | name | desc | category1| category2| category3 | price
Is this possible? If so how?

You could try this to obtain categories in one column (you can split them later):
SELECT p.id as prod_id, * FROM products AS p
GROUP_CONCAT(c.category),
LEFT JOIN Product_UPC AS UPC ON UPC.ProductID = p.id
LEFT JOIN Brands AS b ON p.brand = b.id
LEFT JOIN productCategoryLink AS c ON c.ProductID = p.id
WHERE (p.id = '$this->prod_id')
If you want to get all products, change last row with this
GROUP BY p.id

Related

Inner join Giving columns Multiple values

I have Three Tables In Database
Table : Group
Id, Name
Table : doctor
Id ,DId, DoctorName,
Table : Ratio
Id , DId, UpLimit , downLimit.
When i inner join them , I am Getting duplicate Values to Uplimit and downlimit,,
Actually Group is related to doctors, One group id can have multple doctors,, so when i save some data with Group and doctor, it is saving to all the records with same data, uplimit downlimit varies with different doctors , but when i inner join dem its showing same to all doctors,, how to skip uplimit and downlimit how to write the Query..
Select A.Group , B.doctor , C.Uplimit, D.downlimit from Group A
inner join Doctor B
on A.id = B.id
inner join C ratio
on A.id = c.id
issue is When i separately check it with doctor id in doctor table it is showing only one record, when i inner join them its showing same data to all doctors to particular
how to join them??
Please use the DISTINCT clause after SELECT. This will filter the duplicates.
Select DISTINCT A.[Group] , B.doctor , C.Uplimit, D.downlimit
FROM Group A
inner join Doctor B
on A.id = B.id
inner join Ratio C
on B.id = C.id
It is good to avoid using the keywords as table/column names.
You Table Structure must be like
Table : Group
Id, Name
Table : doctor
Id ,DId(foreign key for group table), DoctorName
Table : Ratio
Id(Foreign Key for Doctor Table), UpLimit , downLimit.
Ratio Table is either missing a foreign key or a primary key, assuming Id of Ratio table is foreign key
Select A.Group , B.doctor , C.Uplimit, D.downlimit from Group A
inner join Doctor B
on A.id = B.Did
inner join ratio C
on B.id = c.id
This should give what you needed

Use Count() with self join in SQL Server

I'm working with the northwind database and my exercise is:
Which suppliers offer two products in the same category? Show company name, category and the both product names
My code:
SELECT DISTINCT
c.CategoryID, s.CompanyName, p1.ProductName, p2.ProductName
FROM
Suppliers s
INNER JOIN
Products p1 ON s.SupplierID = p1.SupplierID
INNER JOIN
Products p2 ON p1.CategoryID = p2.CategoryID
AND p1.ProductID <> p2.ProductID
INNER JOIN
Categories c ON p2.CategoryID = c.CategoryID
GROUP BY
c.CategoryID,s.CompanyName, p1.ProductName, p2.ProductName`
How can I filter that with COUNT() I tried to do it with HAVING but I failed.
I'll appreciate some help, which bringing me back on the right way.
Building on Gordon's answer the code below will get all the data you need. If you absolutely have to have both products in the same row, you can use pivot:
select s.CompanyName
,p.ProductName
from Suppliers s
-- This join filters your Suppliers table to only those with two Products in the same Category
inner join (select SupplierID
,CategoryID
from Products
group by SupplierID
,CategoryID
having count(1) = 2
) pc
on(s.SupplierID = pc.SupplierID)
-- This join returns the two products in the Category returned in the join above.
inner join Products p
on(s.SupplierID = p.SupplierID
and pc.CategoryID = p.CategoryID
)
You can get the list of suppliers/categories with exactly two products using a query like this:
select supplierId, categoryId
from products
group by supplierId, categoryId
having count(*) = 2;
Then, write a query to show the supplier and products names, and use the above to filter the results from that query. You can use either exists or an additional join.

T-SQL: Get all, but join on 'not null'

So I'm trying to get all items from a table, and then add some data if there is a joined member, otherwise keep the data empty (null)
What I have is this:
SELECT
t.id AS _id,
m.name AS name
FROM
tableT AS t
INNER JOIN
tableM AS m ON t.m_id = m.id
The tables look like this:
tableT:
id m.id
----------------
1 NULL
2 1
3 NULL
tableM:
id name
----------------
1 'Bob'
The desired result should be this:
id name
------------------
1 NULL
2 'Bob'
3 NULL
How can I achieve this, as far as I can see inner join won't join on NULL values since they can't be matched
You're looking for a LEFT JOIN
SELECT
t.id AS _id,
m.name AS name
FROM tableT AS t
LEFT JOIN
tableM AS m
ON t.m_id = m.id
The definition of an INNER JOIN will only return data where there is a match in both tables, if one table has missing data then that row will not be returned.
A LEFT JOIN will get all data from the first table and only matching records in the second table, allowing for NULL values.
A little further reading if it's useful;
http://www.w3schools.com/sql/sql_join_left.asp
use LEFT JOIN:
SELECT
t.id AS _id,
m.name AS name
FROM tableT AS t
LEFT OUTER JOIN
tableM AS m
ON t.m_id = m.id
Your requirement is Left Join:
SELECT
t.id AS _id,
m.name AS name
FROM tableT AS t
LEFT OUTER JOIN
tableM AS m
ON t.m_id = m.id
Please check below link for more information regarding different type of joins.
https://msdn.microsoft.com/en-us/library/zt8wzxy4.aspx

SQL SERVER MULTIPLE JOIN: avoid duplicate values

I have 3 tables in my db:-
Customer:
CId | CName | CLocation | CJoinDate
Payment:
TxnId | TxStatus | TxComment | TxAmount | CId | TxDate
Appointment:
AppId | AppCode | CId | ADate | AComment
When I do a Left join with two tables then the calculated results come right. But when I try to do join with 3 tables then the result calculated is wrong.
for eg:-
If I try this query then the total amount calculated is correct:
SELECT c.CName, sum(p.TxAmount)
FROM Customer c LEFT JOIN Payment p ON c.CId = p.CId
WHERE p.TxStatus = 1
GROUP BY c.CName;
In the above query I am just joining two tables which gives me the correct result.
Now when I want to show all the records in one table so I had to join 3 tables.
Below is the query I tried:
SELECT c.CName as Name, sum(p.TxAmount) as Payment, count(distinct a.ADate) as Total_Visit
FROM Customer c LEFT JOIN Payment p ON c.CId = p.CId LEFT JOIN Appointment a ON c.CId = a.CId
WHERE p.TxStatus = 1
GROUP BY c.CName;
The above query gives me wrong Payment amount for each customers. The reason for the wrong result is the Appointments table has more rows as compared to Payment table for each customer. So to show all the appointment entries, the payment amount gets duplicated coz of which the calculation gets wrong.
How can I fix the above scenario witht the above query.
Tks
EDIT: Actually theres 2-3 more tables which I have to join similiar to Appointment table along with a GROUP BY clause for each month.
EDIT1: Fixed it by multiple CTE. Thanks for your valuable pointers it was indeed helpful.
Use a simple CTE expression if you are sure that your sum is calculated correctly by the first query
WITH cte AS
(
SELECT c.CName, c.CID, sum(p.TxAmount) AS sumAmount
FROM Customer c LEFT JOIN Payment p ON c.CId = p.CId
WHERE p.TxStatus = 1
GROUP BY c.CName, c.CID
)
SELECT cte.CName, cte.sumAmount, count(distinct a.ADate) as Total_Visit
FROM cte LEFT JOIN Appointment a ON c.CId = a.CId
GROUP BY c.CName, cte.sumAmount
Try to use a sub query:
SELECT
c.CName as Name
, sum(p.TxAmount) as Payment
, Total_Visit = (SELECT count(distinct a.ADate) FROM Appointment a ON c.CId = a.CId)
FROM Customer c
LEFT JOIN Payment p ON c.CId = p.CId
WHERE p.TxStatus = 1
GROUP BY c.CName;
You can calculate total_visit per CId and then join the subquery
SELECT
c.CName as Name
, sum(p.TxAmount) as Payment
, Total_Visit
FROM Customer c
LEFT JOIN Payment p ON c.CId = p.CId
LEFT JOIN (SELECT a.CId, count(distinct a.ADate) Total_visit FROM Appointment a group by a.CId) as a on c.CId = a.CId
WHERE p.TxStatus = 1
GROUP BY c.CName;

SQL category tree - category, categoryrelationship and product tables - need totals of products for each subcat

I have a Category table which has 3 fields i'm interested in:
ID, Name, CategoryType
The root nodes are identified by having CategoryType of 1, subnodes of the root nodes are of type 2 and sub-sub nodes are of type 3.
There's a 2nd table, CategoryRelationship, of which the two columns that matter are:
CategoryID, ParentCategoryID.
What I would like is a listing of records so that we have the name of each category/subcategory and it's ID, like below
ID RootName1 ID SubName1 ID Sub-SubName1
ID RootName1 ID SubName1 ID Sub-SubName2
ID RootName1 ID SubName2 ID Sub-SubName1
ID RootName1 ID SubName2 ID Sub-SubName2
ID RootName1 ID SubName2 ID Sub-SubName3
ID RootName2 ID SubName1 ID Sub-SubName1
ID RootName2 ID SubName2
ID RootName2 ID SubName3
The ID would be of each root and node/subnode etc
I think I've got this working - i was just wondering if this is the 'correct' way of doing this or if this a better way. This is being done against an MS SQL 2012 express db.
select c.id,
c.name,
c1.Name,
cr1.CategoryID,
c2.Name,
cr2.CategoryID
from Category c
left outer join CategoryRelationship cr1 on cr1.CategoryParentID = c.id
left outer join CategoryRelationship cr2 on cr2.CategoryParentID = cr1.CategoryID
inner join Category c1 on c1.ID = cr1.CategoryID
inner join Category c2 on c2.id = cr2.CategoryID
where c.CategoryTypeID = 1
order by c.name, c1.name, c2.name
There's one more bit to this I need a little help with. There's a 3rd table that has products in it. Each product has a SubCateoryID which would match up to cr2.CategoryID above. I would like to display the total number of items in the Product table for each cr2 category and i still want to include any categories that have no items in the product table. I'm not sure how to do that last part.
I think I have this:
select c.ID, c.Name, c1.Name, cr1.CategoryID, c2.Name, cr2.CategoryID,
(select count(*) from Product where product.SubcategoryID = cr2.CategoryID and Deleted = 0 and StatusID = 1)
from Category c
left outer join CategoryRelationship cr1 on cr1.CategoryParentID = c.id
left outer join CategoryRelationship cr2 on cr2.CategoryParentID = cr1.CategoryID
inner join Category c1 on c1.ID = cr1.CategoryID
inner join Category c2 on c2.id = cr2.CategoryID
where c.CategoryTypeID = 1
order by c.name, c1.name, c2.name

Resources