Find two consecutive rows - sql

I'm trying to write a query that will pull back the two most recent rows from the Bill table where the Estimated flag is true. The catch is that these need to be consecutive bills.
To put it shortly, I need to enter a row in another table if a Bill has been estimated for the last two bill cycles.
I'd like to do this without a cursor, if possible, since I am working with a sizable amount of data and this has to run fairly often.
Edit
There is an AUTOINCREMENT(1,1) column on the table. Without giving away too much of the table structure, the table is essentially of the structure:
CREATE TABLE Bills (
BillId INT AUTOINCREMENT(1,1,) PRIMARY KEY,
Estimated BIT NOT NULL,
InvoiceDate DATETIME NOT NULL
)
So you might have a set of results like:
BillId AccountId Estimated InvoiceDate
-------------------- -------------------- --------- -----------------------
1111196 1234567 1 2008-09-03 00:00:00.000
1111195 1234567 0 2008-08-06 00:00:00.000
1111194 1234567 0 2008-07-03 00:00:00.000
1111193 1234567 0 2008-06-04 00:00:00.000
1111192 1234567 1 2008-05-05 00:00:00.000
1111191 1234567 0 2008-04-04 00:00:00.000
1111190 1234567 1 2008-03-05 00:00:00.000
1111189 1234567 0 2008-02-05 00:00:00.000
1111188 1234567 1 2008-01-07 00:00:00.000
1111187 1234567 1 2007-12-04 00:00:00.000
1111186 1234567 0 2007-11-01 00:00:00.000
1111185 1234567 0 2007-10-01 00:00:00.000
1111184 1234567 1 2007-08-30 00:00:00.000
1111183 1234567 0 2007-08-01 00:00:00.000
1111182 1234567 1 2007-07-02 00:00:00.000
1111181 1234567 0 2007-06-01 00:00:00.000
1111180 1234567 1 2007-05-02 00:00:00.000
1111179 1234567 0 2007-03-30 00:00:00.000
1111178 1234567 1 2007-03-02 00:00:00.000
1111177 1234567 0 2007-02-01 00:00:00.000
1111176 1234567 1 2007-01-03 00:00:00.000
1111175 1234567 0 2006-11-29 00:00:00.000
In this case, only records 1111188 and 1111187 would be consecutive.

Assuming the rows have sequential IDs, something like this may be what you're looking for:
select top 1 *
from
Bills b1
inner join Bills b2 on b1.id = b2.id - 1
where
b1.IsEstimate = 1 and b2.IsEstimate = 1
order by
b1.BillDate desc

select top 2 *
from bills
where estimated = 1
order by billdate desc

You should be able to do a descensing sorted query on estimated = true and select top 2. I am not the best at SQL so i cant give exact language structure

Do you have a column for "statement number", e.g., if Q12008 was statement 28 for a particular customer, then Q22008's bill would be 29, Q32008's bill would be 30 (assuming quarterly billing). You could then check that the statement numbers were adjacent rather than having to do date manipulation.

Related

Apply a discount to order if user already ordered something else

I have a table with users, a table with levels, a table for submitted orders and processed orders.
Here's what the submitted orders looks like:
OrderId UserId Level_Name Discounted_Price Order_Date Price
1 1 OLE Core 0 2020-11-01 00:00:00.000 19.99
2 1 Xandadu 1 2020-11-01 00:00:00.000 0
3 2 Xandadu 0 2020-12-05 00:00:00.000 5
4 1 Eldorado 1 2021-01-31 00:00:00.000 9
5 2 Eldorado 0 2021-02-20 00:00:00.000 10
6 2 Birmingham Blues NULL 2021-07-10 00:00:00.000 NULL
What I am trying to do:
UserId 2 has an order for Birmingham Blues, they have already ordered Eldorado and so qualify for a discount on their Birmingham Blues order. Is there a way to check the entire table for this similarity, and if it exists update the discounted price to a 1 and change the price to lets say 10 for the Birmingham Blues order.
EDIT: I have researched the use of cursors, which I'm sure will do the job but they seem complicated and was hoping a simpler solution would be possible. A lot of threads seem to also avoid using cursors. I also looked at this question: T-SQL: Deleting all duplicate rows but keeping one and was thinking I could potentially use the answer to that in some way.
Based on your description and further comments, the following should hopefully meet your requirements - updating the row for the specified User where the values are currently NULL and the user has a qualifying existing order:
update s set
s.Discounted_Price = 1,
Price = 10
from submitted_Orders s
where s.userId=2
and s.Level_Name = 'Birmingham Blues'
and s.discounted_Price is null
and s.Price is null
and exists (
select * from submitted_orders so
where so.userId = s.userId
and so.Level_name = 'Eldorado'
and so.Order_Date < s.OrderDate
);

Creating a new calculated column in SQL

Is there a way to find the solution so that I need for 2 days, there are 2 UD's because there are June 24 2 times and for the rest there are single days.
I am showing the expected output here:
Primary key UD Date
-------------------------------------------
1 123 2015-06-24 00:00:00.000
6 456 2015-06-24 00:00:00.000
2 123 2015-06-25 00:00:00.000
3 658 2015-06-26 00:00:00.000
4 598 2015-06-27 00:00:00.000
5 156 2015-06-28 00:00:00.000
No of times Number of days
-----------------------------
4 1
2 2
The logic is 4 users are there who used the application on 1 day and there are 2 userd who used the application on 2 days
You can use two levels of aggregation:
select cnt, count(*)
from (select date, count(*) as cnt
from t
group by date
) d
group by cnt
order by cnt desc;

Writing SQL INSERT which retrieves its data from two separate related rows

I am writing a SQL script that is to insert a new record using data from two rows that are under the same AccountID.
My table looks like the following:
AccountID | ActivityId | DisplayDetails | TransactionDate | EnvironmentId
============================================================================
1 7 Display1 2015-02-02 00:00:00.000 1
1 8 DisplayThis1 2018-02-02 00:00:00.000 1
1 7 Display2 1999-02-02 00:00:00.000 2
1 8 DisplayThis2 2000-02-02 00:00:00.000 2
My fix is to find find each 7,8 combination and insert a new row with ActivityId 78 that gets the DisplayDetails from ActivityId 7 and TransactionDate from ActivityId 8.
My queries looks like the following:
SELECT *
INTO #ActivityEight
FROM Account A
WHERE A.ActivityId = 8
INSERT INTO #Account (AccountId, ActivityId, DisplayDetails, TransactionDate)
SELECT VL.AccountId, 78, S.DisplayDetails, VL.TransactionDate
FROM #temp2 VL WITH(NOLOCK)
JOIN #ActivityEight S
ON VL.AccountId = S.AccountId
WHERE VL.ActivityId = 7
However when I run SELECT * FROM Account I get a 78 row for each 7 and 8 row, when I should only get 1 78 row per 7 and 8 combination.
AccountID | ActivityId | DisplayDetails | TransactionDate | EnvironmentId
=============================================================================
1 7 Display1 2015-02-02 00:00:00.000 1
1 8 DisplayThis1 2018-02-02 00:00:00.000 1
1 7 Display2 1999-02-02 00:00:00.000 2
1 8 DisplayThis2 2000-02-02 00:00:00.000 2
1 78 DisplayThis1 2015-02-02 00:00:00.000 NULL
1 78 DisplayThis2 2015-02-02 00:00:00.000 NULL
1 78 DisplayThis1 1999-02-02 00:00:00.000 NULL
1 78 DisplayThis2 1999-02-02 00:00:00.000 NULL
I believe I can utilize the EnvironmentId to achieve the desired functionality, but I'm not sure how.
Any help would be appreciated.
Thanks!
I think this will help you
INSERT INTO #Account (AccountId, ActivityId, DisplayDetails, TransactionDate)
SELECT VL.AccountId, 78, S.DisplayDetails, VL.TransactionDate
FROM Account VL WITH(NOLOCK)
JOIN Account S ON VL.AccountId = S.AccountId and VL.EnvironmentId = S.EnvironmentId
WHERE VL.ActivityId = 7 and S.ActivityId = 8

SQL Query to extract Average Quantity

I want to calculate the average quantity customer purchases in one basket
(Where 1 Basket = Multitple purchases in 1 day)
from the table transaction and update it into cust360.average_basket_Qty
Transactions:-
Trasactions_ID cust_id Tran_date Qty Total_amt
80712190438 270351 2014-02-28 00:00:00.000 5 4265.3
29258453508 270384 2014-02-27 00:00:00.000 5 8270.925
51750724947 273420 2014-02-24 00:00:00.000 2 1748.11
93274880719 271509 2014-02-24 00:00:00.000 3 4518.345
51750724947 273420 2014-02-23 00:00:00.000 2 1748.11
97439039119 272357 2014-02-23 00:00:00.000 2 1821.04
45649838090 273667 2014-02-22 00:00:00.000 1 1602.25
Cust360 Table: -
Cust_id Gender Age Basket_count Total_sale Date Average_basket_Qty
266783 M 525 0 3113 2013-02-20 NULL
266784 F 314 1 5694 2012-12-04 NULL
266785 F 392 0 21613 2013-08-01 NULL
266788 F 551 0 6092 2013-02-12 NULL
266794 F 564 1 27981 2014-02-12 NULL
Following query should work for you
UPDATE DEST
SET DEST.Average_basket_Qty = SRC.AVG_QTY
FROM Cust360 DEST
INNER JOIN
(
SELECT CUST_ID, CAST(TRAN_DATE AS DATE), AVG(QTY) AVG_QTY
FROM Transactions
GROUP BY CUST_ID,CAST(TRAN_DATE AS DATE)
) SRC ON SRC.CUST_ID=DEST.Cust_id

SQL - Some result when no row

I have a table (DATA), from which I would like to perform some simple math queries
Security Date Price
-------- ---- ------
1 2017-08-31 130
2 2017-08-31 150
1 2017-07-31 115
2 2017-07-31 140
1 2017-06-30 100
2 2017-06-30 130
1 2017-05-31 90
1 2017-04-30 85
1 2017-03-31 80
SELECT x.Security, x.Price/y.Price-1 'MONTHLY RETURN', x.Price/z.Price-1 'QUARTERLY RETURN'
FROM DATA AS x
JOIN DATA AS y
ON x.Security = y.Security
JOIN DATA AS z
ON x.Security = z.Security
WHERE x.Security IN (1,2)
AND x.Date = '2017-08-31'
AND y.Date = '2017-07-31'
AND z.Date = '2017-05-31'
I would like to have full table, even when there is no result (150/NO ROW)-1
Security MONTHLY RETURN QUARTERLY RETURN
-------- -------------- ----------------
1 (130/115)-1 (130/90)-1
2 (150/140)-1 NULL or any other data
Instead SQL is returning results just for Security 1 as there is no data (NO ROW) for Security 2 for '2017-05-31'. However it is not a good solution as I have data for '2017-07-31' so I would like to see them for Security 2.
Result of my query:
Security MONTHLY RETURN QUARTERLY RETURN
-------- -------------- ----------------
1 (130/150)-1 (130/90)-1
Is there any way to somehow prepare a table in which I will have all the data and let's say NULL when there is no result. Please note that normally I will have 20 or 30 securities.
I will be grateful for your assist on this one.
This is my second month with SQL and it is a way better than at the beginning but I still have some issues with logic. Do you know any good literature to start with?