Sum of SQL Function return value - sql

I have a SQL Query:
Select Top 3 dbo.FN_GetLRExpenseAmount(VendorBillID,LRNo,PM.PickupRunsheetNo)
From PickupRunsheetMaster PM Left Outer Join
PickupRunsheetDetail PRD
ON PM.PickupRunsheetNo = PRD.PickupRunsheetNo
Where ISNULL(VendorBillID,0) > 0
Output:
601.90
14.56
145.62
When I sum the return value of function dbo.FN_GetLRExpenseAmount(VendorBillID,LRNo,PM.PickupRunsheetNo) throuth below query then it does not return any value
Select Top 3 SUM(dbo.FN_GetLRExpenseAmount(VendorBillID, LRNo, PM.PickupRunsheetNo))
From PickupRunsheetMaster PM Left Outer Join
PickupRunsheetDetail PRD
ON PM.PickupRunsheetNo = PRD.PickupRunsheetNo
Where ISNULL(VendorBillID,0) > 0

The queries are not the same. The TOP 3 does nothing in the second query, because it is an aggregation query that returns only one row.
For an equivalent query, use a subquery or CTE:
select sum(val) as sum_3
from (Select Top 3 dbo.FN_GetLRExpenseAmount(VendorBillID, LRNo, PM.PickupRunsheetNo) as val
From PickupRunsheetMaster PM Left Outer Join
PickupRunsheetDetail PRD
ON PM.PickupRunsheetNo = PRD.PickupRunsheetNo
Where ISNULL(VendorBillID,0) > 0
) x

TOP 3 SUM gives you this result. To get the sum value of the top 3 records you want, Create a subquery:
SELECT
SUM(A.Expense)
FROM
(
Select Top 3 dbo.FN_GetLRExpenseAmount(VendorBillID, LRNo, PM.PickupRunsheetNo) AS [Expense]
From PickupRunsheetMaster PM Left Outer Join
PickupRunsheetDetail PRD
ON PM.PickupRunsheetNo = PRD.PickupRunsheetNo
Where ISNULL(VendorBillID,0) > 0
) AS A

Related

What is outer apply in SQL?

select *
from Kosten_Test a
left join T_Pflege_Parameter pv on pv.Parameterbezeichnung = 'Dummy' and pv.Parametereigenschaft = 'Dummy3'
left join T_Pflege_Parameter pp on pp.Parameterbezeichnung = 'Dummy2' and pp.Parametereigenschaft = a.Herkunft
outer apply( select max(VarianteID) as VarianteID, MerkmalTyp, MerkmalWert
from Test2
where MerkmalTyp = pv.Parameterwert and MerkmalWert = sku
group by MerkmalWert, MerkmalTyp
union
select max(VarianteID) as VarianteID, MerkmalTyp, MerkmalWert
from Testvariante_ASIN_SKU
where MerkmalTyp = pv.Parameterwert and MerkmalWert = a.asin
group by MerkmalWert, MerkmalTyp
) vm
left join (select distinct bundleid from T_Archiv_BundleKomponente) bk on bk.BundleID = vm.VarianteID
Because of the Outer Apply Statement i become always double results. Who can help?
Outer apply is not like a LEFT JOIN. It will apply all the values from the OUTER APPLY Statement to the data joined against.
If your query without the outer apply returns 5 rows and the outer apply query returns 5 rows then the resulting dataset would contain 25 records with each record from the outer apply joined to each row of the other data.
Often times data would be condensed down using aggregations of the values returned from the outer apply query grouped inside of the main query.
Example -
Q1
----
A
B
C
OuterApplyQuery
-----------------
1
2
3
SELECT * FROM Q1 OUTER APPLY (SELECT * FROM OuterApplyQuery) AS X
Result
---------
A 1
A 2
A 3
B 1
B 2
B 3
C 1
C 2
C 3

Left outer join column name ambiguously defined

I have a table task
select
sts_id,
count(*) mycount
from
task
where
sts_id in (1, 8, 39)
group by sts_id;
output :
sts_id count
1 1
8 1
39 1
I have one more temp table with one column sts_id
which looks like this
sts_id
1
8
39
40
41.
I am trying for a left join for both the tables
select
in_list.sts_id,
count(*) mycount
from
task
left outer join
in_list
on task.sts_id = in_list.sts_id
group by sts_id;
to get ab o/p like
1 1
8 1
39 1
40 0
41 0..
I am getting an error of column ambiguously defined.
You are using left join the wrong way (on the left it must be the table with all the rows you want to show).
Count (task.sts_id) to get 0 on rows without ocurrences on that table
select
in_list.sts_id,
count(task.sts_id) mycount
from
in_list
left outer join
task
on in_list.sts_id = task.sts_id
AND task.sts_id in (1, 8, 39) -- Thanks Matt.
group by in_list.sts_id;
You are missing the table alias in the GROUP BY clause.
However, your needed result says that you need to change your join logic: the starting table should be in_list, while task should be in left outer join:
select ...
from in_list
left outer join task
select
in_list.sts_id,
coalesce(count(task.sts_ID),0) mycount --changed this line
from
task
right outer join --changed this line
in_list
on task.sts_id = in_list.sts_id
group by in_list.sts_id; -- changed this line
Reasons:
as in_list contains more data than task, we needed to either change the table order or make it a right join
Count would count all records and not return resutls you want the count from task
need to coalesce the results otherwise null count will return null not 0.
I got my answer with this query
select t2.sts_id, count(t.sts_id)
from task t, in_list t2
where t2.sts_id = t.sts_id(+)
group by t2.sts_id
Thanks,

SQL Access 2003 create column if exisit value

I've three table
Product
- ID_Product
UP
- ID_Product
- UP_SUM
DOWN
- ID_Product
- DOWN_SUM
The query on this three tables create a column Total_SUM = [UP_SUM]-[DOWN_SUM]
The problem is that if there is no value in DOWN_SUM there is no result in Total_SUM.
EX.
UP
1 - 2
2 - 4
3 - 2
DOWN
1 - 1
3 - 1
TOTAL_SUM
(1) 1
(2) 4 -> value missing
(3) 1
In the fact i don't get the value for the ID 2.
How can i use statement if not isNULL to get all values in TOTAL_SUM? Actually the SQL Query is:
SELECT
Product.ID_Product,
UP.UP_SUM,
DOWN.DOWN_SUM,
[UP_SUM]-[DOWN_SUM] AS TOTAL_SUM,
FROM (PRODUCT INNER JOIN UP ON Product.ID_Product = UP.ID_Product)
INNER JOIN DOWN ON Product.ID_Product = DOWN.ID_Product;
use the iif condition that will replace null with a value, and use left outer join since normal join is filtering those rows without a match. A left join will keep them with the values NULL
IIF(ISNULL(DOWN.DOWN_SUM),0,DOWN.DOWN_SUM)
SELECT
Product.ID_Product,
IIF(ISNULL(UP.UP_SUM),0,UP.UP_SUM),
IIF(ISNULL(DOWN.DOWN_SUM),0,DOWN.DOWN_SUM),
IIF(ISNULL(UP.UP_SUM),0,UP.UP_SUM)-IIF(ISNULL(DOWN.DOWN_SUM),0,DOWN.DOWN_SUM) AS TOTAL_SUM,
FROM (PRODUCT LEFT OUTER JOIN UP ON Product.ID_Product = UP.ID_Product)
LEFT OUTER JOIN DOWN ON Product.ID_Product = DOWN.ID_Product;

SQL Server 2005 - cross apply, tvf, and update/delete

How can I make something like this
select
a.atest, a.btest, a.ctest, b.atest, b.btest
from
test.dbo.rm a(nolock)
cross apply
wat.dbo.ar(a.atest,a.btest) b
where
a.rmd = 9 and a.btest > 0
alter function ar(#atest varchar(25), #btest numeric(19,5))
returns table as
return
(
select atest, btest from test.dbo.rm (nolock)
where rmd = 1 and atest=#atest and btest=#btest
)
with delete statement or update. I don't want to make duplicates so after I choose one b.atest I want to delete the record with b.atest or set b.btest to 0. This query is working on table that contain about 5-10 million of records.. so it must be quick.
Use query without function:
select a.atest,a.btest,a.ctest,b.atest,b.btest
from test.dbo.rm a(nolock)
cross apply (
select top 1 atest, btest
from test.dbo.rm t (nolock)
where t.rmd = 1 and t.atest=a.atest and t.btest=a.btest
)b
where a.rmd = 9 and a.btest > 0
You can also use Left join instead of cross apply:
select *
from (
select a.atest,a.btest,a.ctest,b.atest,b.btest,
row_number() over ( partition by b.atest, b.btest order by b.id) as row
from test.dbo.rm a(nolock)
LEFT JOIN test.dbo.rm b ON b.rmd = 1 and b.atest=a.atest and b.btest=a.btest
where a.rmd = 9 and a.btest > 0
)z
where z.row = 1

CTE with Group By returning the same results as basic query

I'm trying to select a count of product reviews by rating, where the rating can be 0 - 5.
The following basic select works but won't give a count of ratings that don't exist in the underlying table.
SELECT Rating, COUNT(*) AS 'Reviews' FROM ProductReviews
WHERE ProductID = 'product1'
GROUP BY Rating
I've tried using a CTE to generate the missing results, joined to Reviews table using an outer join, as soon as I try to include the "group by" expression the results fall back to match the results from the basic query.
(I've checked that the CTE does indeed generate the full range of required values).
BEGIN
DECLARE #START AS INT = 0;
DECLARE #END AS INT = 5;
WITH CTE_Ratings AS
(
SELECT #START as cte_rating
UNION ALL
SELECT 1 + cte_rating
FROM CTE_Ratings
WHERE cte_rating < #END
)
SELECT
cte_rating AS 'ReviewRating'
, ISNULL(COUNT(*), 0) AS 'ReviewCount'
FROM CTE_Ratings
LEFT OUTER JOIN Reviews ON Reviews.Rating = cte_rating
WHERE ProductReviews.ProductID = 'product1'
AND cte_rating BETWEEN #START AND #END
GROUP BY cte_rating
END
(I also tried building a temporary table containing the required values, joined to the Reviews table, with identical results).
In the case of both of the above queries the results are:
Rating Reviews
0 1
3 3
4 9
5 47
Whereas what I'm trying to get to for the same data is:
Rating Reviews
0 1
1 0
2 0
3 3
4 9
5 47
Can anyone suggest when the addition of the Group By aggregate function is causing the query to fail, or how it might be improved ?
The WHERE changes the OUTER JOIN to an INNER JOIN because you are filtering on optional rows from the outer table.So, move the outer table filter into the JOIN
Also, you are already filtering between start and end in the CTE
WITH ...
-- CTE here
SELECT
C.cte_rating AS 'ReviewRating'
, ISNULL(COUNT(PR.Rating), 0) AS 'ReviewCount'
FROM
CTE_Ratings C
LEFT OUTER JOIN
ProductReviews PR ON C.cte_rating= PR.Rating AND PR.ProductID = 'product1'
GROUP BY
C.cte_rating
More clearly, you are actually doing this
WITH ...
-- CTE here
SELECT
C.cte_rating AS 'ReviewRating'
, ISNULL(COUNT(PR.Rating), 0) AS 'ReviewCount'
FROM
CTE_Ratings C
LEFT OUTER JOIN
(
SELECT PR.Rating
FROM ProductReviews
WHERE ProductID = 'product1'
) PR ON C.cte_rating= PR.Rating
GROUP BY
C.cte_rating