SQL - INSERT AND UPDATE Table from a Temp Table - sql

I am trying to insert some data into a Temp Table(#temptable) and after inserting I would Like to perform Sum(amount) which matches the same ID and group by the cust name and the bill ID and I want to select the earliest date available in those matching ID. After all these Operations I would like to update the original table(billtable)
Bill ID Amount CUstName Duedate
12 12.2 ABC 12222016
12 22.2 ABC 12112016
13 23.22 ABC 12102016
Bill ID Amount CUstName Duedate
12 34.4 ABC 12112016
13 23.22 ABC 12102016

you will need something like the below
If(OBJECT_ID('tempdb..#t') Is Not Null)
Begin
Drop Table #t
End
create table #t
(
billid varchar (50),
amount decimal,
cust varchar (50),
duedate datetime
)
insert into #t (billid,amount,cust,duedate) values ('12',12.2,'abc','20161222')
insert into #t (billid,amount,cust,duedate) values ('12',22.2,'abc','20161211')
insert into #t (billid,amount,cust,duedate) values ('13',23.22,'abc','20161210')
insert into #t (billid,amount,cust,duedate) values ('12',34.4,'abc','20161211')
insert into #t (billid,amount,cust,duedate) values ('13',23.22,'abc','20161210')
select billid,sum(amount),MIN(duedate)
from #t
group by billid

Related

How to retrieve SCOPE_IDENTITY of all inserts done in INSERT INTO [table] SELECT [col1, ...] [duplicate]

This question already has answers here:
SQL Server - Return value after INSERT
(14 answers)
Closed 7 months ago.
Suppose I have a temp table with some cols one of which I have dedicated to identity column of the inserted Invoice and the others for inserting Invoice data itself. Like the following table :
CREATE TABLE #InvoiceItems
(
RowNumber INT, -- Used for inserting new invoice
SaleID INT, -- Used for inserting new invoice
BuyerID INT, -- Used for inserting new invoice
InvoiceID INT -- Intended for PK of the invoice added after inserting it
);
I use something like the following for inserting data into Invoice table
INSERT INTO [Invoice]
SELECT [col1, ...]
FROM #InvoiceItems
How can I achieve to fill the InvoiceID column while inserting table data into Invoice table using temp table? I know about SCOPE_IDENTITY() function but it returns the last inserted PK only which does not really suit my need.
I could also use a while to do this one by one but since the number of data I'm planning to insert is immense, I feel like it's not going to be the most optimized option.
Thanks for the answers in advance.
To grab multiple IDENTITY values from INSERT INTO SELECT FROM OUTPUT clause could be used:
-- temp table
CREATE TABLE #temp(col VARCHAR(100));
INSERT INTO #temp(col) VALUES ('A'), ('B'), ('C');
--target table
CREATE TABLE tab(
id INT IDENTITY,
col VARCHAR(100)
);
Main insert:
INSERT INTO tab(col)
OUTPUT inserted.id, inserted.col
SELECT col
FROM #temp;
The output could be also Inserted into another table using OUTPUT INTO:
CREATE TABLE #temp_identity(id INT);
INSERT INTO tab(col)
OUTPUT inserted.id
INTO #temp_identity
SELECT col
FROM #temp;
SELECT * FROM #temp_identity;
db<>fiddle demo
CREATE TABLE #InvoiceItems(
RowNumber INT,
SaleID INT,
BuyerID INT,
InvoiceID INT
);
INSERT INTO #InvoiceItems (RowNumber, SaleID, BuyerID) values (1, 55, 77)
INSERT INTO #InvoiceItems (RowNumber, SaleID, BuyerID) values (1, 56, 78)
INSERT INTO #InvoiceItems (RowNumber, SaleID, BuyerID) values (1, 57, 79)
INSERT INTO #InvoiceItems (RowNumber, SaleID, BuyerID) values (1, 58, 80)
INSERT INTO #InvoiceItems (RowNumber, SaleID, BuyerID) values (1, 59, 81)
DECLARE #Inserted table( RowNumber int,
SaleID INT,
BuyerID INT,
InvoiceID INT);
INSERT INTO dbo.[Invoice] (RowNumber, SaleID, BuyerID)
OUTPUT INSERTED.RowNumber, INSERTED.SaleID, INSERTED.BuyerID, INSERTED.InvoiceID
INTO #Inserted
SELECT RowNumber, SaleID, BuyerID
FROM #InvoiceItems
UPDATE ii
SET InvoiceID = ins.InvoiceID
FROM #InvoiceItems ii
JOIN #Inserted ins on ins.BuyerID = ii.BuyerID and ins.RowNumber = ii.RowNumber and ins.SaleID = ii.SaleID
SELECT * FROM #InvoiceItems

How to return one row with multiple column values?

I'm trying to create a report with one row per customer, however there are multiple rows per customer.
The current view is:
Customer Business Dept Type Status
-----------------------------------------------
019 Public null null null
019 null IT null null
019 null null Retail 0 --char(1)
My desired view is:
Customer Business Dept Type Status
-----------------------------------------------
019 Public IT Retail 0
I'm using SQL Server 2008 R2. There are more columns in my data set, but this is a sample. I'm unsure of how to achieve the results when my datatype is character and not INT based.
If this is a representative example, and each column will always have a single row with a value and the others will have nulls, you could use an aggregate max or min, which ignore nulls:
SELECT customer, MAX(business), MAX(dept), MAX(type), MAX(status)
FROM mytable
GROUP BY customer
try something this:
CREATE TABLE #tmp ([Customer] CHAR(3), [Business] VARCHAR(20), [Dept] VARCHAR(20), [Type] VARCHAR(20), [Status] CHAR(1))
INSERT INTO #tmp (Customer, Business) VALUES ( '019', 'Public')
INSERT INTO #tmp (Customer,Dept) VALUES ('019','IT')
INSERT INTO #tmp (Customer,[Type]) VALUES ('019','Retail')
INSERT INTO #tmp (Customer,[Status]) VALUES ('019','0')
SELECT * FROM #tmp AS t
SELECT t.Customer, t.Business, t2.Dept, t3.[Type], t4.[Status] FROM #tmp AS t
JOIN #tmp AS t2 ON t2.Customer = t.Customer
JOIN #tmp AS t3 ON t3.Customer = t.Customer
JOIN #tmp AS t4 ON t4.Customer = t.Customer
WHERE t.Business IS NOT NULL AND t2.Dept IS NOT NULL AND t3.[Type] IS NOT NULL AND t4.[Status] IS NOT NULL

SQL - Update column for each duplicate in other column

I'm looking for an SQL query to update a column to the same Id for each duplicate in another column and then delete each overwritten row from another table.
For example
I have:
IndustryId ProductId ExternalId
144 3332 13
147 3423 13
148 3532 13
2637 63199 32
121 2789 32
I want:
IndustryId ProductId ExternalId
144 3332 13
147 3332 13
148 3332 13
2637 63199 32
121 63199 32
I also need to record the overwritten ProductId values so that I can delete those rows in another table (3423, 3532, and 2789 should be deleted in the other table). Could be in more than one query if neccesary, that doesnt matter.
What is the best way to achieve this?
That isn't too tough, especially if you break out the steps.
Check this out:
if object_id('tempdb..#myData') is not null
drop table #myData;
create table #myData ( industryid int, productId int, externalId int);
insert into #myData (industryId, productId, externalId)
values (144,3332,13);
insert into #myData (industryId, productId, externalId)
values (147,3423,13);
insert into #myData (industryId, productId, externalId)
values (148,3532,13);
insert into #myData (industryId, productId, externalId)
values (2637,63199,32);
insert into #myData (industryId, productId, externalId)
values (121,2789,32);
--select * from #myData;
-------------------------------------------------
if object_id('tempdb..#IdsToKeep') is not null
drop table #IdsToKeep;
if object_id('tempdb..#badRows') is not null
drop table #badRows;
create table #IdsToKeep (externalId int, productId int);
create table #badRows ( industryId int, productId int, externalId int);
insert into #IdsToKeep
select
externalId, min(productId)
from
#myData
group by
externalId;
--- Capture rows that will be changed ---
insert into #badRows
select
md.industryId, md.productId, md.externalId
from
#myData md
left join #IdsToKeep itk on
md.externalId = itk.externalId
and
md.productId = itk.productId
where
itk.productId IS NULL
;
--- Make the update to the main table ---
update
#myData
set
productId = itk.productId
from
#myData
inner join #IdsToKeep itk on #myData.externalId = itk.externalId
;
----------
select * from #mydata;
select * from #badRows;
declare #table table (IndustryId int, ProductId int, ExternalId int) insert into #table values (144,3332,13), (147,3423,13), (148,3532,13), (2637,63199,32), (121,2789,32)
select * from #table
;with cte (productid, externalid) as (select max(productid), ExternalId from #table group by ExternalId) select t.IndustryId, c.productid, c.externalid from cte c right outer join #table t on c.externalid = t.ExternalId

SQL Server Getting where an data object was based in a Period of Time given Track Info

I have a doubt on how to conclude this in SQL Server 2008 R2.
I have a table that has some inputs and this inputs have a Parent tag and a timestamp.
Sometimes these objects have their parent Tag changed in a timestamp. This parent tag can change from time to time.
Let´s suppose that I have the table below. My current table has millions of data with different ObjectIDs. Seeing the Table, it is easy to see that the ParentID was changed in the timestamps 3 to 4, 6 to 7 and 8 to 9.
ProductID ParentID DateID value
-------- --------- ------- -------------
100 1 1 325,2
100 1 2 326,2
100 1 3 329,6
100 2 4 335,2
100 2 5 336,5
100 2 6 338,3
100 3 7 339,2
100 3 8 342,1
100 1 9 343,7
100 1 10 355,6
100 1 11 385,8
The Answer I want is to which ParentID the ObjectID belonged and the Start and End timestamp and what was the delta value between the timestamps (Timestamp = TS)
ProductID ParentID DateID_Start DateID_End DeltaValue
-------- --------- ---------- -------- ----------
100 1 1 4 10,0
100 2 4 7 4,0
100 3 7 9 4,5
100 1 9 11 42,1
What I have Accomplish so far is getting when there is a change, but it only gives me the changes, but not the table above.
ObjectID ParentID_Old ParentID_New DateID_Changed
-------- ------------ ------------ ------------
100 1 2 3 to 4
100 2 3 6 to 7
100 3 1 8 to 9
Here are the code to generate the table and the test inserts. Below as well is the Select to get the changes.
--Initial Insert Code
IF OBJECT_ID('tempdb..#Trackings') Is Not Null
Drop table #Trackings
Create Table #Trackings
(
ProductID bigint
, value float
, StoreID int
, DateID int
, Aux_Row_Number int
)
Insert into #Trackings(ProductID,StoreID,DateID,value,Aux_Row_Number) Values (100,1,1,325.2,1)
Insert into #Trackings(ProductID,StoreID,DateID,value,Aux_Row_Number) Values (100,1,2,326.2,2)
Insert into #Trackings(ProductID,StoreID,DateID,value,Aux_Row_Number) Values (100,1,3,329.6,3)
Insert into #Trackings(ProductID,StoreID,DateID,value,Aux_Row_Number) Values (100,2,4,335.2,4)
Insert into #Trackings(ProductID,StoreID,DateID,value,Aux_Row_Number) Values (100,2,5,336.5,5)
Insert into #Trackings(ProductID,StoreID,DateID,value,Aux_Row_Number) Values (100,2,6,338.3,6)
Insert into #Trackings(ProductID,StoreID,DateID,value,Aux_Row_Number) Values (100,3,7,339.2,7)
Insert into #Trackings(ProductID,StoreID,DateID,value,Aux_Row_Number) Values (100,3,8,342.1,8)
Insert into #Trackings(ProductID,StoreID,DateID,value,Aux_Row_Number) Values (100,1,9,343.7,9)
Insert into #Trackings(ProductID,StoreID,DateID,value,Aux_Row_Number) Values (100,1,10,355.0,10)
Insert into #Trackings(ProductID,StoreID,DateID,value,Aux_Row_Number) Values (100,1,12,385.0,12)
Insert into #Trackings(ProductID,StoreID,DateID,value,Aux_Row_Number) Values (100,3,13,485.0,13)
Insert into #Trackings(ProductID,StoreID,DateID,value,Aux_Row_Number) Values (100,3,14,985.0,14)
Insert into #Trackings(ProductID,StoreID,DateID,value,Aux_Row_Number) Values (100,3,15,1585.0,15)
Insert into #Trackings(ProductID,StoreID,DateID,value,Aux_Row_Number) Values (100,3,16,3585.0,16)
Insert into #Trackings(ProductID,StoreID,DateID,value,Aux_Row_Number) Values (100,2,17,5585.0,17)
Insert into #Trackings(ProductID,StoreID,DateID,value,Aux_Row_Number) Values (100,2,18,6585.0,18)
Insert into #Trackings(ProductID,StoreID,DateID,value,Aux_Row_Number) Values (100,2,19,8585.0,19)
Insert into #Trackings(ProductID,StoreID,DateID,value,Aux_Row_Number) Values (100,2,20,9585.0,20)
And the SQL to get the changes I am using:
Select ISNULL(A.StoreID,-1)
, ISNULL(B.StoreID,-1)
, A.ProductID
, A.value
, B.value
, A.DateID
, B.DateID
From #Trackings A
Join #Trackings B
On A.ProductID = B.ProductID
And A.Aux_Row_Number + 1 = B.Aux_Row_Number
And ISNULL(A.StoreID,-1) <> ISNULL(B.StoreID,-1)
Any lights ideas Guys?
Thanks in advance!
EDITED: Just a little bit more "Business" info: ParentID would be like a store a product is and DateID the Time that it arrived there. So let's suppose that productID 100 is in the ParentID 1, it means that in the DateID 1 the productID 100 entered in Store 1. So for some reason it moved to Store 2 in DatedID 4. So my first row in the answer table means that ProductID 100 was in the StoreID 1 from DateID 1 up to DateID 4. The productID 100 then stayed in StoredID 2 from DateID 4 up to 7, then changed to StoredID 3 and finally it came back to StoreID 1 from DateID 9 up to our last DateID in the DateID range "selected". So that's why the answer table has 2 lines with ParentID 1.
OK, try this, using your updated sample data:
Declare #Trackings table
(
ProductID bigint
, value float
, StoreID int
, DateID int
, Aux_Row_Number int
)
Insert into #Trackings(ProductID,StoreID,DateID,value,Aux_Row_Number) Values (100,1,1,325.2,1)
Insert into #Trackings(ProductID,StoreID,DateID,value,Aux_Row_Number) Values (100,1,2,326.2,2)
Insert into #Trackings(ProductID,StoreID,DateID,value,Aux_Row_Number) Values (100,1,3,329.6,3)
Insert into #Trackings(ProductID,StoreID,DateID,value,Aux_Row_Number) Values (100,2,4,335.2,4)
Insert into #Trackings(ProductID,StoreID,DateID,value,Aux_Row_Number) Values (100,2,5,336.5,5)
Insert into #Trackings(ProductID,StoreID,DateID,value,Aux_Row_Number) Values (100,2,6,338.3,6)
Insert into #Trackings(ProductID,StoreID,DateID,value,Aux_Row_Number) Values (100,3,7,339.2,7)
Insert into #Trackings(ProductID,StoreID,DateID,value,Aux_Row_Number) Values (100,3,8,342.1,8)
Insert into #Trackings(ProductID,StoreID,DateID,value,Aux_Row_Number) Values (100,1,9,343.7,9)
Insert into #Trackings(ProductID,StoreID,DateID,value,Aux_Row_Number) Values (100,1,10,355.0,10)
Insert into #Trackings(ProductID,StoreID,DateID,value,Aux_Row_Number) Values (100,1,12,385.0,12)
Insert into #Trackings(ProductID,StoreID,DateID,value,Aux_Row_Number) Values (100,3,13,485.0,13)
Insert into #Trackings(ProductID,StoreID,DateID,value,Aux_Row_Number) Values (100,3,14,985.0,14)
Insert into #Trackings(ProductID,StoreID,DateID,value,Aux_Row_Number) Values (100,3,15,1585.0,15)
Insert into #Trackings(ProductID,StoreID,DateID,value,Aux_Row_Number) Values (100,3,16,3585.0,16)
Insert into #Trackings(ProductID,StoreID,DateID,value,Aux_Row_Number) Values (100,2,17,5585.0,17)
Insert into #Trackings(ProductID,StoreID,DateID,value,Aux_Row_Number) Values (100,2,18,6585.0,18)
Insert into #Trackings(ProductID,StoreID,DateID,value,Aux_Row_Number) Values (100,2,19,8585.0,19)
Insert into #Trackings(ProductID,StoreID,DateID,value,Aux_Row_Number) Values (100,2,20,9585.0,20)
;
with t
as (select *, ROW_NUMBER() over (order by dateid) as rn
from #Trackings ),
cte1
(Productid,
Storeid,
DateID,
value,
rn,
set1)
as
(select ProductID, StoreID, DateID, value, rn , 1
from t
where rn = 1
union all
select t.productID, t.storeID, t.dateID, t.value, t.rn,
case when
cte1.Storeid = t.storeID then cte1.set1 else cte1.set1+1 end
from t join cte1 on t.rn = cte1.rn+1)
,
t2 as (select Productid, Storeid, set1, MIN(CAST(DateID as int)) as tmi, max(dateid) as tma
from cte1
group by Productid, Storeid, set1)
select t3.Productid, t3.Storeid, t3.set1, t3.date_min, t3.date_max, u.value - t.value
from
(select a.Productid, a.Storeid, a.set1, a.tmi as date_min, coalesce(b.tmi, a.tma) as date_max
from t2 a left join t2 b
on a.set1 + 1 = b.set1) t3 join #Trackings t
on t3.date_min = t.DateID
join #Trackings u
on t3.date_max = u.DateID
order by set1
The "Value" column confused me, as you are using commas (,) instead of periods (.) to separate the integer from the decimal part of your float.
I finally found a solution that based on my Initial Table has a better performance than using CTE and as sugested by https://stackoverflow.com/users/2522030/mike-abramczyk (the real table has 5k entries and using the his suggestion was taking a long time).
After querying the search table, I added two lines to the table for each ProductID. These lines would receive a dummy StoreID (i.e. -9999): one with a Min(DateID) - 1 and another One with a Max(DateID) + 1.
Insert into #Trackings (Aux_Row_Number,StoreID,DateID,ProductID,value)
Select Min(Aux_Row_Number)-1 Aux_Row_Number,-9999 as StoreID, min(DateID)-1 as DateID,ProductID,Min(value)
From #Trackings
group by ProductID
Order by ProductID
Insert into #Trackings (Aux_Row_Number,StoreID,DateID,ProductID,value)
Select Max(Aux_Row_Number)+1 Aux_Row_Number,-9999 as StoreID, max(DateID)+1 as DateID,ProductID,Max(value)
From #Trackings
group by ProductID
Order by ProductID
Then, I used the Query I posted to get the changes. So I could get the Change from Dummy(-9999) to the real StoreID (1) and the last change from a real StoreID(3) to Dummy(-9999).
select ISNULL(A.StoreID,-1)
, ISNULL(B.StoreID,-1)
, A.ProductID
, A.value
, B.value
, A.DateID
, B.DateID
, ROW_NUMBER() OVER (Partition by B.ProductID Order by A.DateID)
from #Trackings A
Join #Trackings B
On A.ProductID = B.ProductID
And A.Aux_Row_Number + 1 = B.Aux_Row_Number
AND ISNULL(A.StoreID,0) <> ISNULL(B.StoreID ,0)
This was the Crucial Step! Now I have I can create the result table with the DateIDs of the changes I was looking for. The Aux_Row_Number Column helped get a sequence in the changes to each product using (think that the last query has create the table #ProductStoreChanges - I will be posting the entire Soltion below):
select A.ID_FinalStore,A.DateID_Final,B.DateID_Final,A.ProductID,B.value_2,A.value_2,B.value_2 - A.value_2 DeltaValue
from #ProductStoreChanges A
Join #ProductStoreChanges B
On (A.Aux_Row_Number + 1 = B.Aux_Row_Number)
And A.ProductID = B.ProductID
Order by A.DateID_Final
Here is the Final Solution:
IF OBJECT_ID('tempdb..#Trackings') Is Not Null
Drop table #Trackings
IF OBJECT_ID('tempdb..#ProductStoreChanges') Is Not Null
Drop table #ProductStoreChanges
Create Table #Trackings
(
ProductID bigint
, value float
, StoreID int
, DateID int
, Aux_Row_Number int
, flg_changed bit Default(0)
)
Insert into #Trackings(ProductID,StoreID,DateID,value,Aux_Row_Number) Values (100,1,1,325.2,1)
Insert into #Trackings(ProductID,StoreID,DateID,value,Aux_Row_Number) Values (100,1,2,326.2,2)
Insert into #Trackings(ProductID,StoreID,DateID,value,Aux_Row_Number) Values (100,1,3,329.6,3)
Insert into #Trackings(ProductID,StoreID,DateID,value,Aux_Row_Number) Values (100,2,4,335.2,4)
Insert into #Trackings(ProductID,StoreID,DateID,value,Aux_Row_Number) Values (100,2,5,336.5,5)
Insert into #Trackings(ProductID,StoreID,DateID,value,Aux_Row_Number) Values (100,2,6,338.3,6)
Insert into #Trackings(ProductID,StoreID,DateID,value,Aux_Row_Number) Values (100,3,7,339.2,7)
Insert into #Trackings(ProductID,StoreID,DateID,value,Aux_Row_Number) Values (100,3,8,342.1,8)
Insert into #Trackings(ProductID,StoreID,DateID,value,Aux_Row_Number) Values (100,1,9,343.7,9)
Insert into #Trackings(ProductID,StoreID,DateID,value,Aux_Row_Number) Values (100,1,10,355.0,10)
Insert into #Trackings(ProductID,StoreID,DateID,value,Aux_Row_Number) Values (100,1,12,385.0,12)
Insert into #Trackings(ProductID,StoreID,DateID,value,Aux_Row_Number) Values (100,3,13,485.0,13)
Insert into #Trackings(ProductID,StoreID,DateID,value,Aux_Row_Number) Values (100,3,14,985.0,14)
Insert into #Trackings(ProductID,StoreID,DateID,value,Aux_Row_Number) Values (100,3,15,1585.0,15)
Insert into #Trackings(ProductID,StoreID,DateID,value,Aux_Row_Number) Values (100,3,16,3585.0,16)
Insert into #Trackings(ProductID,StoreID,DateID,value,Aux_Row_Number) Values (100,2,17,5585.0,17)
Insert into #Trackings(ProductID,StoreID,DateID,value,Aux_Row_Number) Values (100,2,18,6585.0,18)
Insert into #Trackings(ProductID,StoreID,DateID,value,Aux_Row_Number) Values (100,2,19,8585.0,19)
Insert into #Trackings(ProductID,StoreID,DateID,value,Aux_Row_Number) Values (100,2,20,9585.0,20)
Insert into #Trackings (Aux_Row_Number,StoreID,DateID,ProductID,value)
Select Min(Aux_Row_Number)-1 Aux_Row_Number,-9999 as StoreID, min(DateID)-1 as DateID,ProductID,Min(value)
From #Trackings
group by ProductID
Order by ProductID
Insert into #Trackings (Aux_Row_Number,StoreID,DateID,ProductID,value)
Select Max(Aux_Row_Number)+1 Aux_Row_Number,-9999 as StoreID, max(DateID)+1 as DateID,ProductID,Max(value)
From #Trackings
group by ProductID
Order by ProductID
CREATE TABLE #ProductStoreChanges
(
ID_InitialStore INT
, ID_FinalStore INT
, ProductID INT
, value_1 BIGINT
, value_2 BIGINT
, DateID_Initial BIGINT
, DateID_Final BIGINT
, Aux_Row_Number INT
)
INSERT INTO #ProductStoreChanges
(
ID_InitialStore
, ID_FinalStore
, ProductID
, value_1
, value_2
, DateID_Initial
, DateID_Final
, Aux_Row_Number
)
select ISNULL(A.StoreID,-1)
, ISNULL(B.StoreID,-1)
, A.ProductID
, A.value
, B.value
, A.DateID
, B.DateID
, ROW_NUMBER() OVER (Partition by B.ProductID Order by A.DateID)
from #Trackings A
Join #Trackings B
On A.ProductID = B.ProductID
And A.Aux_Row_Number + 1 = B.Aux_Row_Number
AND ISNULL(A.StoreID,0) <> ISNULL(B.StoreID ,0)
select A.ID_FinalStore,A.DateID_Final,B.DateID_Final,A.ProductID,B.value_2,A.value_2,B.value_2 - A.value_2 DeltaValue
from #ProductStoreChanges A
Join #ProductStoreChanges B
On (A.Aux_Row_Number + 1 = B.Aux_Row_Number)
And A.ProductID = B.ProductID
Order by A.DateID_Final

Subquery: how to retrieve the last non-zero value from a column?

Considering a table customerBalance with 3 columns: name, date and balance. Suppose a set of records like:
cus_name cus_date cus_balance
John 06/14/2011 1000
John 06/15/2011 500
John 06/16/2011 0
Mary 06/14/2011 3000
Mary 06/15/2011 2800
Mary 06/16/2011 0
How to create a SQL query which returns, for the date 6/16/2011 instead 0, the last non-zero value based on date (in sample, $500 for John and $2800 for Mary)?
I'm trying to do it using a subquery which uses Max function to retrieve the last date with non-zero value, but I didn't succeed. This example is quite "nonsensical", but I really need to do an operation like this in my dataset. Thanks!
Note: If you can specify the DB and version this query can be improved.
Try this:
SELECT *
FROM customers
WHERE (cus_name, cus_date)
IN
(
SELECT cus_name, MAX(cus_date)
FROM customers
WHERE cus_balance <> 0
GROUP BY cus_name
)
Update: Alternate version:
SELECT a.*
FROM customers a,
(
SELECT cus_name, MAX(cus_date)
FROM customers
WHERE cus_balance <> 0
GROUP BY cus_name
) b
WHERE a.cus_name = b.cus_name
AND a.cus_date = b.cus_date
Here it goes:
CREATE Table #temp
(
Cus_Name VARCHAR(200) NULL,
Cus_Date Char(8) NULL,
Cus_Balance INT NULL
)
INSERT INTO #temp VALUES ('John' , '20110614' ,1000 )
INSERT INTO #temp VALUES ('John' , '20110615' , 500 )
INSERT INTO #temp VALUES ('John' , '20110616' , 0 )
INSERT INTO #temp VALUES ('Mary' , '20110614' ,3000 )
INSERT INTO #temp VALUES ('Mary' , '20110615' ,2800 )
INSERT INTO #temp VALUES ('Mary' , '20110616' , 0 )
SELECT
T.Cus_Name ,
MIN(t.Cus_Balance)
FROM #temp t
WHERE t.Cus_Balance <>0
GROUP BY t.Cus_Name
DROP TABLE #temp