sql server top query - sql

I don't know what's wrong with this query :
select * from products , top 1 * from pic
where products.productId = pic.productId
I have Products and Pic tables , every products could have 1 to n pic and I would like to return every product and the first pic of that
The picture of diagram may help

You need to have a way of uniquely identifying each pic, so I'm asuming that table as an ID column...
SELECT
*
FROM
products
LEFT JOIN
pic
ON pic.Id = (SELECT TOP 1 id FROM pic WHERE productID = products.ProductID ORDER BY id DESC)
EDIT
Inspired by another answer, using APPLY instead...
SELECT
*
FROM
products
OUTER APPLY
(SELECT TOP 1 * FROM pic WHERE productID = products.ProductID ORDER BY id DESC) AS pic

You need a subquery to
select the first PicID's for each ProductID
join with Pic table itself to get the additional columns
join with Products to get the product columns
SQL Statement
SELECT *
FROM Products prod
LEFT OUTER JOIN Pic p ON p.ProductID = prod.ProductID
LEFT OUTER JOIN (
SELECT PicID = MIN(PicID)
, ProductID
FROM Pic
GROUP BY
ProductID
) pm ON pm.PicID = p.PicID

There is also way with subsection but please avoid sub select as much as You can in yours TSQL
Select
*
,(select top(1) adress from pic where pic.productid=products.id /* if u wanna you also can order by id */ ) as Id
from products

Related

I want to do inner join of some colums but still show the other colums if thats possible

basically i have a quest to do where i have to get all the details (product_purchase,price_history ,product colums that are name,type,id and price)from just searching for a product id.i basically did
select price_history.product_id, product.id, product_purchase.product_id from ((price_history
inner join product on price_history.product_id = product.id)
inner join product_purchase on price_history.product_id = product_purchase.product_id);
right now it just gives me the product id from product_purchase price_history and the id from product and i wanted it to show all the other colums from the 3 tables and want to have an option where i can do an input of the id something like
where product.id= %s
Try this.
SELECT *
FROM price_history
INNER JOIN product
ON price_history.product_id = product.id
INNER JOIN product_purchase
ON price_history.product_id = product_purchase.product_id
WHERE product_id = %substitutedParameter%
But, as you will see, SELECT * gives you some redundant columns. It's good practice to name the columns you want in your SELECT.... something like this, I guess.
SELECT price_history.product_id,
product.description,
product_purchase.vendor
...

How can I perform this sql update using sql instead of using code?

I have been able to select this data, using these two sql queries
Query 1:
SELECT article_id, amount_required, amount_sold FROM products_articles,sales WHERE sales.product_id = products_articles.product_id
Query 2:
SELECT * FROM articles
What I want to do, is go through the first table (with amount sold and required) (it's fine that there are duplicate rows), and for each row in the table multiply the value of amount_sold and amount_required and then subtract that value from amount_in_stock where the ids match in the second table.
Example from the first row:
2 * 4 = 8, change amount_in_stock from 124 to 116.
And so on...
How can I do this using just sql?
UPDATE A
SET
A.amount_in_stock =(S.amountSold * S.amount_required)- A.amount_in_stock
FROM articles AS A
INNER JOIN
products_articles AS PA
ON PA.article_id= A.article_id
INNER JOIN Sales AS S
ON S.product_id=PA.product_id
Please try this:
Update articles a
inner join
(
SELECT article_id, sum(amount_required) amount_required, sum(amount_sold )amount_sold FROM products_articles inner join sales on sales.product_id = products_articles.product_id
group by article_id
)b on a.article_id=b.article_id
set a.amount_in_stock=a.amount_in_stock-(amount_required*amount_sold )
Since there could be multiple rows in product_articles and amount_sold I have used group by to sum the amounts.
For SQLite please try this:
Update articles
set amount_in_stock=(SELECT sum(amount_required) * sum(amount_sold ) FROM products_articles inner join sales on sales.product_id = products_articles.product_id
where products_articles.article_id=articles.article_id
group by article_id
)
where exists (SELECT * FROM products_articles inner join sales on sales.product_id = products_articles.product_id where products_articles.article_id=articles.article_id
)

Joining complex sql oracle select queries

I have a complex query that selects product id values from history and orders.
SELECT ProductID
FROM History h ( SELECT .....) LATEST
WHERE h.ProductId = LATEST.ProductID
AND ....
AND IsActive = true;
This query is too long, so I could not write all of it. But it returns a table like this:
ProdutID
--------
4654654
9879879
5465465
2132188
7894215
....
I want to join this product id result another table that containts ProductId column.
SELECT * FROM MySecondTable;
ProductID Color
--------- -----
4654654 red
9879879 blue
5465465 orange
How can I join these two query?
CTEs are a really simple way to do such a thing:
with t as (<your query here>)
select t.*, t2.color
from t join
MySecondTable t2
on t.ProductId = t2.ProductId;
You could also just add the join to the from clause of the original query.
you could use the firts as inner joined table
SELECT b.*
FROM MySecondTable b
INNER JOIN (
SELECT ProductID
FROM History h ( SELECT .....) LATEST
WHERE h.ProductId = LATEST.ProductID
AND ....
AND IsActive = true;
) t on t.ProductID = b.ProductID

Returning ID's from two other tables or null if no IDs found using using a left join SQL Server

I am wondering if someone could hep me. I am trying to make a join on two tables and return an id if an id is there but if there is no id return null but still return the row for that product and not ignore it. My query below returns twice the amount the records to which I can not figure out why.
SELECT
T2.ProductID, FirstChild.SupplierID, SecondChild.AccountID
FROM
Products T2
LEFT OUTER JOIN
(
SELECT TOP(1) SupplierID, Reference,CompanyID, Row_Number() OVER (Partition By SupplierID Order By SupplierID) AS RowNo FROM Suppliers
)
FirstChild ON T2.SupplierReference = FirstChild.Reference AND RowNo = 1AND FirstChild.CompanyID =T2.CompanyID
LEFT OUTER JOIN
(
SELECT TOP(1) AccountID, SageKey,CompanyID, Row_Number() OVER (Partition By AccountID Order By AccountID) AS RowNo2 FROM Accounts
)
SecondChild ON T2.ProductAccountReference = SecondChild.Reference AND RowNo2 = 1 AND SecondChild.CompanyID =T2.CompanyID
Example of what I am trying to do
ProductID SupplierID AccountID
1 5 2
2 6 NULL
3 NULL NULL
OUTER APPLY and ditching the ROW_NUMBER Seems like a better choice here:
SELECT
p.ProductId
,FirstChild.SupplierId
,SecondChild.AccountId
FROM
Products p
OUTER APPLY (SELECT TOP (1) s.SupplierId
FROM
Suppliers s
WHERE
p.SupplierReference = s.SupplierReference
AND p.CompanyId = s.CompanyId
ORDER BY
s.SupplierId
) FirstChild
OUTER APPLY (SELECT TOP (1) a.AccountId
FROM
Accounts
WHERE
p.ProductAccountReference = a.Reference
AND p.CompanyId = a.CompanyId
ORDER BY
a.AccountID
) SecondChild
The way your query is written above there is no correlation for the derived tables. Which means you would always get what ever SupplierId SQL chooses based on optimization and if that doesn't happen to always be Row1 you wont get the value. You need to relate your Table and select top 1, adding an ORDER BY in your derived table is like identifying the row number you want.
If it's just showing duplicate records, wouldn't an inelegant solution just be to add distinct in the select line?

Join two tables where all child records of first table match all child records of second table

I have four tables: Customer, CustomerCategory, Limit, and LimitCategory. A customer can be in multiple categories and a limit can also have multiple categories. I need to write a query that will return the customer name and limit amount where ALL the customers categories match ALL the limit categories.
I'm guessing it would be similar to the answer here, but I can't seem to get it right. Thanks!
Edit - Here's what the tables look like:
tblCustomer
customerId
name
tblCustomerCategory
customerId
categoryId
tblLimit
limitId
limit
tblLimitCategory
limitId
categoryId
I THINK you're looking for:
SELECT *
FROM CustomerCategory
LEFT OUTER JOIN Customer
ON CustomerCategory.CustomerId = Customer.Id
INNER JOIN LimitCategory
ON CustomerCategory.CategoryId = LimitCategory.CategoryId
LEFT OUTER JOIN Limit
ON Limit.Id = LimitCategory.LimitId
Updated!
Thanks to Felix for pointing out a flaw in my existing solution (3 years after I originally posted it, hehe). After looking at it again, I think this might be correct. Here I'm getting (1) the customers and limits with matching categories, plus the number of matching categories, (2) the number of categories per customer, (3) the number of categories per limit, (4) I then ensure the number of categories for customer and limits is the same as the number of the matches between the customers and limits:
UNTESTED!
select
matches.name,
matches.limit
from (
select
c.name,
c.customerId,
l.limit,
l.limitId,
count(*) over(partition by cc.customerId, lc.limitId) as matchCount
from tblCustomer c
join tblCustomerCategory cc on c.customerId = cc.customerId
join tblLimitCategory lc on cc.categoryId = lc.categoryId
join tblLimit l on lc.limitId = l.limitId
) as matches
join (
select
cc.customerId,
count(*) as categoryCount
from tblCustomerCategory cc
group by cc.customerId
) as customerCategories
on matches.customerId = customerCategories.customerId
join (
select
lc.limitId,
count(*) as categoryCount
from tblLimitCategory lc
group by lc.limitId
) as limitCategories
on matches.limitId = limitCategories.limitId
where matches.matchCount = customerCategories.categoryCount
and matches.matchCount = limitCategories.categoryCount
I don't know if this will work or not, just a thought i had and i can't test it, I'm sures theres a nicer way! don't be too harsh :)
SELECT
c.customerId
, l.limitId
FROM
tblCustomer c
CROSS JOIN
tblLimit l
WHERE NOT EXISTS
(
SELECT
lc.limitId
FROM
tblLimitCategory lc
WHERE
lc.limitId = l.id
EXCEPT
SELECT
cc.categoryId
FROM
tblCustomerCategory cc
WHERE
cc.customerId = l.id
)