ssrs hidden rows are getting summed - sql

I am fairly new to SSRS and SQL Server and I need help with the following issue:
I have two tables. One contains the time stamped record of purchases of one single product by a small group of customers. The other table contains the time stamped record of price changes for that product.
Table1
PurchaseDateTime - primary key,
CustCode, kgs
Table2
Price, ChangeDateTime
I can display all required information from the two tables in a tablix using the following query:
SELECT input.purchasedatetime,
input.custcode,
input.kgs,
price.price,
price.changedatetime
FROM input
LEFT OUTER JOIN price
ON input.purchasedatetime > price.changedatetime
However, the query correctly returns the results which includes the superseded prices as well. I could hide those rows, but the totals still sum it all. I could group it by the Price.ChangeDateTime as the third subgroup and then filter it on TopN, but the result is the same. The display is correct, the totals are not, which is probably to be expected since the totals are on the higher level grouping.
I cannot apply the conditions for the visibility to the SUM() as it does not allow aggregates and I am hiding on Previous().
I would prefer the query to do the complete work and I have seen that some other databases implement the LIMIT 1 clause, but here this is not supported.
I am still to try the custom code on the report level, but I am not too familiar with VB code.
I am using the SQL Server 2014 Express and Visual Studio 2013 integrated shell as Data Tools or BI
Any help is much appreciated.

you can get maximum change date time for each purchase time using GROUP BY and MAX
These values can be joined further to get price for each purchase time
SQL Fiddle
with cte
as
(
SELECT input.purchasedatetime, MAX(price.changedatetime) as ChangeDateTime
FROM input
LEFT OUTER JOIN price
ON input.purchasedatetime > price.changedatetime
GROUP BY input.purchasedatetime
)
SELECT input.purchasedatetime,
input.custcode,
input.kgs,
price.price,
price.changedatetime
FROM input
JOIN cte
on input.purchasedatetime = cte.purchasedatetime
left join price
on cte.changedatetime = price.changedatetime

Related

Counting Unique IDs In a LEFT/RIGHT JOIN Query in Access

I am working on a database to track staff productivity. Two of the ways we do that is by monitoring the number of orders they fulfil and by tracking their error rate.
Each order they finish is recorded in a table. In one day they can complete many orders.
It is also possible for a single order to have multiple errors.
I am trying to create a query that provides a summary of their results. This query should have one column with "TotalOrders" and another with "TotalErrors".
I connect the two tables with a LEFT/RIGHT join since not all orders will have errors.
The problem comes when I want to total the number of orders. If someone made multiple mistakes on an order, that order gets counted multiple times; once for each error.
I want to modify my query so that when counting the number of orders it only counts records with distinct OrderID's; yet, in the same query, also count the total errors without losing any.
Is this possible?
Here is my SQL
SELECT Count(tblTickets.TicketID) AS TotalOrders,
Count(tblErrors.ErrorID) AS TotalErrors
FROM tblTickets
LEFT JOIN tblErrors ON tblTickets.TicketID = tblErrors.TicketID;
I have played around with SELECT DISTINCT and UNION but am struggling with the correct syntax in Access. Also, a lot of the examples I have seen are trying to total a single field rather than two fields in different ways.
To be clear when totalling the OrderCount field I want to only count records with DISTINCT TicketID's. When totalling the ErrorCount field I want to count ALL errors.
Ticket = Order.
Query Result: Order Count Too High
Ticket/Order Table: Total of 14 records
Error Table: You can see two errors for the same order on 8th
do a query that counts orders by staff from Orders table and a query that counts errors by staff from Errors table then join those two queries to Staff table (queries can be nested for one long SQL statement)
correlated subqueries
SELECT Staff.*,
(SELECT Count(*) FROM Orders WHERE StaffID = Staff.ID) AS CntOrders,
(SELECT Count(*) FROM Errors WHERE StaffID = Staff.ID) AS CntErrors
FROM Staff;
use DCount() domain aggregate function
Option 1 is probably the most efficient and option 3 the least.

SQL SUM function with added

total novice here with SQL SUM function question. So, SUM function itself works as I expected it to:
select ID, sum(amount)
from table1
group by ID
There are several records for each ID and my goal is to summarize each ID on one row where the next column would give me the summarized amount of column AMOUNT.
This works fine, however I also need to filter out based on certain criteria in the summarized amount field. I.e. only look for results where the summarized amount is either bigger, smaller or between certain number.
This is the part I'm struggling with, as I can't seem to use column AMOUNT, as this messes up summarizing results.
Column name for summarized results is shown as "00002", however using this in the between or > / < clause does not work either. Tried this:
select ID, sum(amount)
from table1
where 00002 > 1000
group by ID
No error message, just blank result, however plenty of summarized results with values over 1000.
Unfortunately not sure on the engine the database runs on, however it should be some IBM-based product.
The WHERE clause will filter individual rows that don't match the condition before aggregating them.
If you want to do post aggregation filtering you need to use the HAVING Clause.
HAVING will apply the filter to the results after being grouped.
select ID, sum(amount)
from table1
group by ID
having sum(amount) > 1000

SQL select record for each id where max year equals value

There is a lot of info on this but nothing seems to match my issue exactly and I am stuck.
I have two tables, 'members' and 'payment_records'. The 'members' table includes a unique member_id as well as other data (address, payment_type etc). The 'payment_records' table includes a unique payment_id, plus the member_id relative to who made the payment, and an expiry_year (eg 2011, 2012, 2013 etc). Each member_id has multiple payment records.
I need to get the records where the MAXIMUM expiry_year for each member_id matches a dynamic value ($year). Right now I am returning records where all members have an expiry_year = $year, even if it's not the MAXIMUM value. For example, Mary might have 2 payments with expiry years of 2013 and 2014, so she shows in my results for $year = 2013, even though her most recent result is 2014. How do I limit it so records are only returned if the maximum expiry_year is = $year?
This is my (simplified) statement now, that returns records with the correct expiry, but doesn't weed out the ones with a newer year:
SELECT members.member_id, payment_records.expiry_year, payment_records.member_id
FROM members inner join payment_records on members.member_id=payment_records.member_id
WHERE member_category='Standard' AND payment_records.expiry_year = $year"
I have tried using a sub statement but am confused as to the correct syntax in amongst my inner join statement. I've also tried using DISTINCT and GROUP BY with ORDER BY but it just gives me blank results.
Any help is appreciated in advance. I am sorry if this is a double-up, I've been searching tutorials till my eyeballs ached with no luck.
You want to use group by and having for this logic:
SELECT members.member_id, MAX(pr.expiry_year)
FROM members m inner join
payment_records pr
on m.member_id = pr.member_id
WHERE m.member_category = 'Standard'
GROUP BY m.member_id
HAVING MAX(pr.expiry_year) = $year;

SQL Inventory Count wont return item name

I am working with our inventory database and I created a query (access 2002 format citrix run server) that counts all items of a type meeting a serviceability status and it runs as I had expected but when I try to display the item name Equipment.Model in the other table which is already left joined via the ID I get the error Tried to execute a query that does not include the specified expression 'model' as part of an aggregate function. I think I would expect to get this if I tried to list something like an asset ID but this is related to the items I am counting. The trouble piece is quoted. The tables are quite large but they are basically the below
Equipment
|EquipmentID|CompanyID|Model|Description|TypeID|...
Inventory
|InventoryID|EquipmentID|Serial|Status|...
SELECT Inventory.EquipmentID, "Equipment.Model", COUNT(*) AS Count
FROM (Inventory LEFT JOIN Equipment ON Inventory.EquipmentID=Equipment.EquipmentID)
WHERE Equipment.TypeID = 14
AND Inventory.Status NOT IN (4,5,6,8)
GROUP BY Inventory.EquipmentID;
SELECT Inventory.EquipmentID, Equipment.Model, COUNT(*) AS Count
FROM Inventory
LEFT JOIN Equipment ON Inventory.EquipmentID=Equipment.EquipmentID
WHERE Equipment.TypeID = 14
AND Inventory.Status NOT IN (4,5,6,8)
GROUP BY Inventory.EquipmentID, Equipment.Model;
You have to use all non aggregate columns in the GROUP BY clause.
You need to include equipment.Model in your group by clause

For Loop in SQL Server 2005 Express?

I have a program using SQL Server 2005 Express and I need some help looping through 2 tables to calculate inventory.
Table 1: stores all products with the inventory total upon setup
Table 2: stores the transactions against all products from table 1
How can I loop through all items in table 2 and subtract that amount from table 1 counts?
If I have my query like this then I get data for each product
SELECT
ii.ItemNum, ii.ItemName, ii.OzOnHand
FROM
dbo.InventoryItems ii
INNER JOIN
dbo.InventoryLog il ON ii.ItemNum = il.InvItemNum
WHERE
ii.active = 1
I need each occurrence from table 2 to be subtracted from table 1's total amount
This is an example of a join to an aggregated table (I think that is the best way to understand it):
SELECT ii.ItemNum, ii.ItemName, ii.OzOnHand, ii.OzOnHand - coalesce(il.cnt, 0)
FROM dbo.InventoryItems ii LEFT JOIN
(select il.InvItemNum, sum(OzRemoved) as cnt
from dbo.InventoryLog il
group by il.InvItemNum
) il
ON ii.ItemNum = il.InvItemNum
WHERE ii.active = 1;
The subquery groups everything in the log and counts the number of entries. If each entry could affect more than one item, then you would use something like sum(cnt) as cnt instead of count(*).
Then, the query uses a left outer join. This type of join ensures that all inventory items remain, even those with nothing in the log. Finally, the count is subtracted from what is available in set up. The coalesce() is to handle the situation where there are no matches in the log table. To avoid getting NULL, the NULL is turned into a 0.