Sum Sql is not working as expected result - sql

I have a view that has values with total on each row plus the date.
I want to sum all the total for each date
V_stock
cd_client
qty
dt
v_stock_sum
select sum(qty), dt
from v_stock
group by (dt)
This gives a ridiculous number, what am i doing wrong, any tip helps thanks
V_stock
cd_client qty dt
LIMA 3360 2017-02-20
v_stock_sum
qty dt
120960 2017-02-20
I expected since there is one line only 3360

probably you have some problems with your view:
try to run count also to check if your view return more then one row
select sum(qty),
count(*) as rows,
dt
from v_stock
group by dt
if you will get more then 1 in the count then you need to check why you got more then one row
also you didn't put any condition on the cd_client
maybe you have only one row for each cd_client

Related

Function to REPLACE* last previous known value for NULL

I want to fill the NULL values with the last given value for that column. A small sample of the data:
2021-08-15 Bulgaria 1081636
2021-08-16 Bulgaria 1084693
2021-08-17 Bulgaria 1089066
2021-08-18 Bulgaria NULL
2021-08-19 Bulgaria NULL
In this example, the NULL values should be 1089066 until I reach the next non-NULL value.
I tried the answer given in this response, but to no avail. Any help would be appreciated, thank you!
EDIT: Sorry, I got sidetracked with trying to return the last value that I forgot my ultimate goal, which is to replace the NULL values with the previous known value.
Therefore the query should be
UPDATE covid_data
SET people_vaccinated = ISNULL(?)
Assuming the number you have is always increasing, you can use MAX aggregate over a window:
SELECT dt
, country
, cnt
, MAX(cnt) OVER (PARTITION BY country ORDER BY dt)
FROM #data
If the number may decrease, the query becomes a little bit more complex as we need to mark the rows that have nulls as belonging to the same group as the last one without a null first:
SELECT dt
, country
, cnt
, SUM(cnt) OVER (PARTITION BY country, partition)
FROM (
SELECT country
, dt
, cnt
, SUM(CASE WHEN cnt IS NULL THEN 0 ELSE 1 END) OVER (PARTITION BY country ORDER BY dt) AS partition
FROM #data
) AS d
ORDER BY dt
Here's a working demo on dbfiddle, it returns the same data with ever increasing amount, but if you change the number for 08-17 to be lower than that of 08-16, you'll see MAX(...) method producing wrong results.
In many datasets it is incorrect to make assumptions about the behaviour of the data in the underlying dataset, if your goal is simply to fill the blanks that might appear mid-way in a dataset then the answer to the post you referenced A:sql server nulls duplicate last known value in table is still one of the best solutions, here is an adaptation:
SELECT dt
, country
, cnt
, ISNULL(source.cnt, excludeNulls.LastCnt)
FROM #data source
OUTER APPLY ( SELECT TOP 1 cnt as LastCnt
FROM #data
WHERE dt < source.dt
AND cnt IS NOT NULL
ORDER BY dt desc) ExcludeNulls
ORDER BY dt
MAX and LAST_VALUE will give you the a value with respect to the entire record set, which would not work with the existing solutions if you had a value for 2021-08-19. In that case the last value would be used to fill the gaps, not the previous non-null value.
When we need to fill in gaps that occur part-way through the results we need to apply a filter to the window query, TOP 1 ... ORDER BY gives us the ability to filter and sort on entirely different fields to the one that we want to capture, but also means that we can display the last value for fields that are not numeric, see this fiddle a few other examples: https://dbfiddle.uk/?rdbms=sqlserver_2019&fiddle=372285d29f97dbb9663e8552af6fb7a2

SQL minimum date value after today's date Now()

I am writing a query and am having trouble filtering data as I would like. In the table, there is a date field and an ItemCode field. I would like to return one record per ItemCode with the earliest date that is after today.
If today is 6/6/2017 and my data looks like:
ItemCode Date
1 6/1/2017
1 6/7/2017
1 6/10/2017
2 6/2/2017
2 6/8/2017
2 6/15/2017
I would want the result to be
ItemCode Date
1 6/7/2017
2 6/8/2017
My query so far is:
SELECT PO_PurchaseOrderDetail.ItemCode, Min(PO_PurchaseOrderDetail.RequiredDate) AS NextPO
FROM PO_PurchaseOrderDetail
GROUP BY PO_PurchaseOrderDetail.ItemCode
HAVING (((Min(PO_PurchaseOrderDetail.RequiredDate))>=Now()));
The problem is that the Min function fires first and grabs the earliest dates per ItemCode, which are before today. Then the >=Now() is evaluated and because the min dates are before today, the query returns nothing.
I've tried putting the >=Now() inside the min function in the HAVING part of the query but it does not change the result.
My structure is wrong and I would appreciate any advice. Thanks!
I would approach like this for standard SQL, Access approach may vary
select PO_PurchaseOrderDetail.ItemCode,
min(PO_PurchaseOrderDetail.RequiredDate) as NextPO
from PO_PurchaseOrderDetail
where PO_PurchaseOrderDetail.RequiredDate >= Now()
group by PO_PurchaseOrderDetail.ItemCode;
Put the date condition in the where clause (not the having clause):
select ItemCode, min(Date) as NextPO
from PO_PurchaseOrderDetail
where Date > '6/6/2017'
group by ItemCode

SQL statement to find Min Date

I am new to SQL so I am fumbling here a bit. I have the following table:
Entered Generalist Item
12/31/2012 07:26:50 Tom Smith RTW/Updates
12/31/2012 07:30:10 Terrie Bradshaw Posters
12/31/2012 07:38:16 Jen Lopez Client Assistance/Request
12/31/2012 07:48:00 Tom Smith RTW/Updates
12/31/2012 07:50:29 Mike Smith RTW/Updates
12/31/2012 07:55:32 Tom Smith Client Assistance/Request
I am trying to find out when was the last time a rep was assigned an item. So I am looking for the Min value on a column. My query would look at Item "RTW/Updates" when was the earlier time entered between a date range and return Tom Smith. For example the user queries, RTW/Update between 12/31/2012 and 1/1/2013 and the answer would be Tom Smith.
This is what I have so far, but have not been able to figure out the between the dates part:
SELECT MIN(entered), generalist, item
FROM dataTable
That is pretty much it.
I May not understand what you want, but if you want to get one person back based on the minimum date, you need to work out the minimum date, and use that to find that person:
select
*
from
datatable
where
entered =
(
select
min(entered) as MinDate
from
DataTable
where
Item = 'RTW/Updates'
)
and item = 'RTW/Updates'
SQL Fiddle
You could also use a CTE:
; with LowDate as
(select
min(entered) as MinDate
from
DataTable
where
Item = 'RTW/Updates' )
select
*
from
datatable
inner join LowDate
ON entered = LowDate.MinDate
and item = 'RTW/Updates'
More SQL Fiddle!
You are looking for the window functions. Here is an example:
select generalist, item, entered
from (SELECT generalist, item, entered,
row_number() over (partition by item order by entered desc) as seqnum
FROM dataTable
) t
where seqnum = 1;
The function row_number() enumerates the rows for each item (based on the partition by clause) starting with 1. The row with 1 is going to have the most recent date, because of the order by clause.
The outer query just selects the rows where the seqnum = 1 -- which is the most recent record for each item.
I believe this should work (where the # variables are the parameters passed to your procedure)
SELECT MIN(entered), generalist, item
FROM dataTable
WHERE item = #itemParm
AND entered BETWEEN #enteredStart AND #enteredEnd
GROUP BY generalist, item
Use GROUP BY
SELECT MAX(entered) MinDate, generalist, item FROM dataTable
GROUP BY Generalist, Item
Just to add something to the answers (which are correct, essentially) before this one : in order to find the latest date, you'll have to use MAX() instead of MIN().
SELECT MIN(entered) MinDate, generalist, item
FROM dataTable
GROUP BY generalist, item
When you have used an aggregate function in your select statement and you are also selecting other column which are not contained in any aggregate function you have to tell sql server how to aggregate that column by adding a GROUP BY clause and mentioning names of all the column that are in SELECT statement but not contained in any Aggregate function.
to get the latest Date you will need to get the Biggest(Largest in Number Date) and you will need to use MAX() function instead of MIN(), MIN() will return the Oldest (smallest Date) in your column.
SELECT MAX(entered) MinDate, generalist, item
FROM dataTable
GROUP BY generalist, item

SQL Picking Top Date out of the Date Field

So I have a table with a date column. I want to be able to group these dates by Item field of some type. For example I might have a column called Item and within the Item field there may be 500 entries. Item 12345 might have 5 entires, each with a price. I want to be able to pull out all of the Items, grouped by the newest date.
031126-2M1 8/10/2011 12:00:00 AM 7.8678
031126-2M1 7/22/2011 12:00:00 AM 9.5620
031126-2M1 7/15/2011 12:00:00 AM 8.8090
In this example, I want to show the item with the closest date, 7/15/2011 so I can use that Price of 8.8090. The list would then show the other items, some may have one entry, others might have many, but I want to show all of them with the closets date. Need Help!
Thanks
A MS SQL Server version...
WITH
sorted_data AS
(
SELECT
ROW_NUMBER() OVER (PARTITION BY item_id ORDER BY item_date DESC) AS row_id,
*
FROM
item_data
WHERE
item_date <= getDate()
)
SELECT * FROM sorted_data WHERE row_id = 1
selct * from table
where This = that
Group by something having This.
order by date desc.
having "THIS" should be in the query itself.
hope this helps..
Cheers

sql to calculate daily totals minues the previous day's totals

I have a table that has a date, item, and quantity.
I need a sql query to return the totals per day, but the total is the quantity minus the previous day totals. The quantity accumulates as the month goes on. So the 1st could have 5 the 2nd have 12 and the 3rd has 20.
So the 1st adds 5
2nd adds 7 to make 12
3rd adds 8 to make 20.
I've done something like this in the past, but can not find it or remember. I know i'll need a correlated sub-query.
TIA
--
Edit 1
I'm using Microsoft Access.
Date is a datetime field,
item is a text, and
quantity is number
--
Edit 2
Ok this is what i have
SELECT oos.report_date, oos.tech, oos.total_cpe, oos_2.total_cpe
FROM oos INNER JOIN (
SELECT oos_2.tech, Sum(oos_2.total_cpe) AS total_cpe
FROM oos_2
WHERE (((oos_2.report_date)<#10/10/2010#))
GROUP BY oos_2.tech
) oos_2 ON oos.tech = oos_2.tech;
How do i get the oos.report_date into where i says #10/10/2010#. I thought I could just stick it in there like mysql, but no luck. I'm gonna continue researching.
Sum them by adding one to the date and making the value negative, thus taking yesterday's total from today's:
SELECT report_date, tech, Sum(total_cpe) AS total_cpe
FROM (
SELECT oos.report_date, oos.tech, oos.total_cpe
FROM oos
UNION ALL
SELECT oos.report_date+1, oos.tech, 0-oos.total_cpe
FROM oos
)
WHERE (report_date < #10/10/2010#)
GROUP BY report_date, tech
ORDER BY report_date, tech
Ok, I figured it out.
SELECT o.report_date, o.tech, o.total_cpe,
o.total_cpe - (
SELECT IIf(Sum(oos.total_cpe) is null, 0,Sum(oos.total_cpe)) AS total_cpe
FROM oos
WHERE (((oos.tech)=o.tech) AND ((oos.report_date)<o.report_date))
) AS total
FROM oos o;