I have a problem with table's iteration. There is status product (test_product) in stock and actions: add or remove from stock.
product
action
operation_date
number
total
test_product
add
2023-01-03
4
4
test_product
remove
2023-01-05
-3
1
test_product
remove
2023-01-07
-1
0
In some day we have add or remove product, number of product and total number.
I want to count number of days, where total number is 0 in some period, let's say from 2023-01-01 to 2023-01-10 with starting value of total column is 0.
In my mind I have table like this:
calendar_day
product
action
operation_day
number
total
2023-01-01
0
2023-01-02
0
2023-01-03
test_product
add
2023-01-03
4
4
2023-01-04
4
2023-01-05
test_product
remove
2023-01-05
-3
1
2023-01-06
1
2023-01-07
test_product
remove
2023-01-07
-1
0
2023-01-08
0
2023-01-09
0
2023-01-10
0
Counting of 0 days is technical operation, it's not important now. Problem is building table.
I've tried something like this:
GO
DECLARE #PRODUCT AS VARCHAR(30)
SET #PRODUCT = 'test_product'
DECLARE #TOTAL AS INT
SET #TOTAL = 0
DECLARE #STOP_DATE AS DATE;
SET #STOP_DATE = CAST('2023-01-10' AS DATE)
DECLARE #UP_DATE AS DATE;
SET #UP_DATE = CAST('2023-01-01' AS DATE);
WHILE #STOP_DATE >= #UP_DATE
BEGIN
SELECT
#UP_DATE AS calendar_day,
CASE
WHEN operation_date = #UP_DATE THEN operation_date
ELSE ''
END AS operation_date,
number,
#TOTAL+number AS total
FROM stock
JOIN products ON products.id = stock.product_id
WHERE products.name = #PRODUCT
AND stock.operation_date >= #UP_DATE
AND stock.operation_date <= #UP_DATE
SET #UP_DATE = DATEADD(DAY, 1, #UP_DATE)
END
But I've got separation result, 7 of them are empty and it's too slow, because we have 9000 items for now.
Can you help me?
You can accomplish to this task into three steps:
build a calendar table with a recursive query, that stops at calen_date < '2023-10-01'
left join the calendar table with your products table
compute a running sum on your number value to get your total.
WITH calendar AS (
SELECT CAST('2023-01-01' AS DATE) AS calendar_day
UNION ALL
SELECT DATEADD(DAY, 1, calendar_day) FROM calendar WHERE calendar_day < '2023-01-10'
)
SELECT calendar_day, product, action_, operation_date, number,
SUM(COALESCE(number,0)) OVER(ORDER BY calendar_day) AS total
FROM calendar c
LEFT JOIN test_product p
ON c.calendar_day = p.operation_date
Output:
calendar_day
product
action
operation_day
number
total
2023-01-01
0
2023-01-02
0
2023-01-03
test_product
add
2023-01-03
4
4
2023-01-04
4
2023-01-05
test_product
remove
2023-01-05
-3
1
2023-01-06
1
2023-01-07
test_product
remove
2023-01-07
-1
0
2023-01-08
0
2023-01-09
0
2023-01-10
0
Check the demo here.
Related
I am trying to get records from previous month's last day to current month's last day with below code
SELECT [DAY],
[N-1 HSD],
[N-2 HSD],
[N-6 HSD],
DIP,
[STOCK LTR],
[PURRCHASE LTR],
[STOCK LTR] + [PURRCHASE LTR] AS [Total Ltr],
Isnull([TESTING], 0) AS Testing,
0 AS [Sales As Reading],
0 AS [Sales As Dip],
0 AS [Diff Ltr],
(SELECT TOP (1) _RATE
FROM _PRODUCTRATE
WHERE _ISDELETED = N'1'
AND _PRODUCTID_PK = N'154eeb16-0c5c-44e4-b5cc-b0f30a22098f'
AND _DATE <= _RATEDATE
ORDER BY _DATE DESC) AS [Rate Rs],
0 AS [Amount Rs]
FROM
(SELECT TOP (100) PERCENT Day(DBO._DSRENTRY._DSRENTRYDATE) AS [Day],
DBO._DSRENTRYDET._CLOSING,
DBO._DSRENTRY._DIPSCALE AS DIP,
DBO._DSRENTRY._DIP AS [Stock Ltr],
DBO._DSRENTRY._TESTINGQTY AS [Testing],
DBO._NOZZLE._NOZZLENAME,
(SELECT Isnull(Sum(_QTY), 0) AS Expr1
FROM DBO._TANKVACCANT
WHERE (_ISDELETED = N'1')
AND (_TANKID_PK = N'88e31d8c-acf5-4c09-a91f-28577c66d070')
AND (_TANKVACCANTDATE = _DSRENTRYDATE)
AND (_COMPANYID_PK = N'747c28ad-2924-4456-91fe-6f4f7b0db3fd')
AND (_WORKGROUPNAME = N'SRV')) AS [Purrchase Ltr],
DBO._DSRENTRY._DSRENTRYDATE AS _RATEDATE
FROM DBO._NOZZLE
RIGHT OUTER JOIN DBO._DSRENTRYDET ON DBO._NOZZLE._NOZZLEID_PK = DBO._DSRENTRYDET._NOZZLEID_PK
RIGHT OUTER JOIN DBO._DSRENTRY ON DBO._DSRENTRYDET._DSRENTRYID_PK = DBO._DSRENTRY._DSRENTRYID_PK
WHERE (DBO._DSRENTRYDET._ISDELETED = N'1')
AND (DBO._DSRENTRY._COMPANYID_PK = N'747c28ad-2924-4456-91fe-6f4f7b0db3fd')
AND (DBO._DSRENTRYDET._COMPANYID_PK = N'747c28ad-2924-4456-91fe-6f4f7b0db3fd')
AND (DBO._NOZZLE._COMPANYID_PK = N'747c28ad-2924-4456-91fe-6f4f7b0db3fd')
AND (DBO._DSRENTRY._WORKGROUPNAME = N'SRV')
AND (DBO._DSRENTRYDET._WORKGROUPNAME = N'SRV')
AND (DBO._NOZZLE._WORKGROUPNAME = N'SRV')
AND (DBO._DSRENTRY._ISDELETED = N'1')
AND (DBO._NOZZLE._ISDELETED = N'1')
AND (DBO._DSRENTRY._DSRENTRYDATE >= CONVERT(DATETIME, '31.08.2017 00:00:00', 105))
AND (DBO._DSRENTRY._DSRENTRYDATE <= CONVERT(DATETIME, '30.09.2017 23:59:59', 105))
AND (DBO._DSRENTRY._TANKID_PK = N'88e31d8c-acf5-4c09-a91f-28577c66d070')
ORDER BY DBO._DSRENTRY._DSRENTRYDATE) AS DERIVEDTBL_1 PIVOT(Sum(_CLOSING)
FOR _NOZZLENAME IN ([N-1 HSD], [N-2 HSD], [N-6 HSD])) AS PVTTABLE
below is the output
DAY N-1 HSD N-2 HSD N-6 HSD DIP STOCK LTR PURRCHASE LTR Total Ltr Testing Sales As Reading Sales As Dip Diff Ltr Rate Rs Amount Rs
1 1886247.00 1139460.00 391836.00 140.00 15319.00 0.00 15319.00 10.00 0 0 0 59.86 0
.........
.........
.........
29 1909720.00 1147850.00 397467.00 102.40 10473.00 0.00 10473.00 10.00 0 0 0 61.57 0
30 1910934.00 1148180.00 397467.00 90.60 8932.00 6000.00 14932.00 10.00 0 0 0 61.65 0
31 1885620.00 1139191.00 391788.00 70.00 6310.00 10000.00 16310.00 10.00 0 0 0 59.78 0
As showing in output the last recod which is 31 1885620.00 1139191.00 391788.00 70.00 6310.00 10000.00 16310.00 10.00 0 0 0 59.78 0 is showing into bottom but this should be first,
If I changed Day(DBO._DSRENTRY._DSRENTRYDATE) to DBO._DSRENTRY._DSRENTRYDATE then records are comming in proper order but its giving me full date and time.
like below
DAY N-1 HSD N-2 HSD N-6 HSD DIP STOCK LTR PURRCHASE LTR Total Ltr Testing Sales As Reading Sales As Dip Diff Ltr Rate Rs Amount Rs
2017-08-31 00:00:00.000 1885620.00 1139191.00 391788.00 70.00 6310.00 10000.00 16310.00 10.00 0 0 0 59.78 0
2017-09-01 00:00:00.000 1886247.00 1139460.00 391836.00 140.00 15319.00 0.00 15319.00 10.00 0 0 0 59.86 0
2017-09-02 00:00:00.000 1887258.00 1139601.00 391938.00 130.00 14062.00 0.00 14062.00 10.00 0 0 0 59.94 0
----------------------------
----------------------------
2017-09-29 00:00:00.000 1909720.00 1147850.00 397467.00 102.40 10473.00 0.00 10473.00 10.00 0 0 0 61.57 0
2017-09-30 00:00:00.000 1910934.00 1148180.00 397467.00 90.60 8932.00 6000.00 14932.00 10.00 0 0 0 61.65 0
But I need only day not full datetime,
How I archived this.
Using DATEPART(DAY, [Day])helps to order your output. Please add it in the select clause and order by the same column to get the sorted output.
We have two columns Id and month Id.
The output what I'm looking for is to divide year from month Id based on quarter granularity. The activity column should be from quarter. If id is active activity should be 1 else 0 .If id comes in any of the 1st quarter (eg:only 1) the activity is still 1 .
Like this:
id month_dt
-----------------------------------
1000000000 2012-03-01 00:00:00.0
1000000000 2015-09-01 00:00:00.0
1000000000 2016-10-01 00:00:00.0
1000000000 2015-11-01 00:00:00.0
1000000000 2014-01-01 00:00:00.0
1000000000 2013-04-01 00:00:00.0
1000000000 2014-12-01 00:00:00.0
1000000000 2015-02-01 00:00:00.0
1000000000 2014-06-01 00:00:00.0
1000000000 2013-01-01 00:00:00.0
1000000000 2014-05-01 00:00:00.0
1000000000 2016-05-01 00:00:00.0
1000000000 2013-07-01 00:00:00.0
What is expected:
ID YEAR QTR ACTIVITY (1 or 0)
--------------------------------------------------
1000000000 2012 1 1
1000000000 2012 2 0
1000000000 2012 3 0
1000000000 2012 4 0
1000000000 2013 1 1
1000000000 2013 2 1
1000000000 2013 3 1
1000000000 2013 4 0
Below is the one I tried but it doesn't return the expected results. Please help me achieve this
SELECT
a.id, a.year,
SUM(CASE WHEN quarter BETWEEN 1 AND 3 THEN 1 ELSE 0 END) AS Q1,
SUM(CASE WHEN quarter BETWEEN 4 AND 6 THEN 1 ELSE 0 END) AS Q2,
SUM(CASE WHEN quarter BETWEEN 7 AND 9 THEN 1 ELSE 0 END) AS Q3,
SUM(CASE WHEN quarter BETWEEN 10 AND 12 THEN 1 ELSE 0 END) AS Q4
FROM
(SELECT
id,
TRIM(SUBSTRING(month_id, 1, 4)) AS year,
TRIM(regexp_replace(SUBSTR(month_id, 5, 4), "-", "")) as quarter
FROM
test.patientid) a
GROUP BY
a.id, a.year
I think you are looking for something like this:
select y.yyyy, q.q,
(case when count(t.month_dt) > 0 then 1 else 0 end) as activity_flag
from (select distinct year(month_dt) as yyyy from t) y cross join
(select distinct quarter(month_dt) as q from t) q left join
t
on year(t.month_dt) = y.yyyy and quarter(t.month_dt) = q.q
group by y.yyyy, q.q;
This assumes that there is at least one activity for each quarter in a year (regardless of the quarter). Otherwise, you just need to put in a list of 1, 2, 3, and 4 to get the quarters.
#Babu; If the function quarter does not exist in your version of hive, I have an alternate function for getting the quarter on a give date. Hope this helps. Thanks!
create table qtrs(qtr int);
insert into qtrs values (1),(2),(3),(4);
create table ims
(id int,
month_dt date
);
insert into ims values
(100, '2012-03-01'),
(100, '2013-04-01'),
(100, '2013-01-01'),
(100, '2013-07-01'),
(100, '2014-01-01'),
(100, '2014-05-01'),
(100, '2014-06-01'),
(100, '2014-12-01'),
(100, '2015-02-01'),
(100, '2015-09-01'),
(100, '2015-11-01'),
(100, '2016-05-01'),
(100, '2016-10-01');
insert into ims values
(200, '2012-03-01'),
(200, '2013-04-01');
Query:
select DISTINCT NVL(ims.id, qtr.id) as id,qtr.year as year,qtr.qtr as qtr,
IF(ims.id is null, 0, 1) as activity
from jbacoy.ims ims
right join (select distinct ims.id,YEAR(ims.month_dt) as year,qtrs.qtr from jbacoy.ims ims join jbacoy.qtrs qtrs) qtr
on (ims.id=qtr.id and year(ims.month_dt)=qtr.year and int((month(month_dt)-1)/3)+1=qtr.qtr)
sort by id, year, qtr;
Result:
id year qtr activity
100 2012 1 1
100 2012 2 0
100 2012 3 0
100 2012 4 0
100 2013 1 1
100 2013 2 1
100 2013 3 1
100 2013 4 0
100 2014 1 1
100 2014 2 1
100 2014 3 0
100 2014 4 1
100 2015 1 1
100 2015 2 0
100 2015 3 1
100 2015 4 1
100 2016 1 0
100 2016 2 1
100 2016 3 0
100 2016 4 1
200 2012 1 1
200 2012 2 0
200 2012 3 0
200 2012 4 0
200 2013 1 0
200 2013 2 1
200 2013 3 0
200 2013 4 0
This is a two part question. I have a base table that looks like this:
DATE ID START_DATE QTY ROW
2011-01-31 1 2009-04-30 40 1
2011-01-31 1 2009-10-31 5 2
2011-01-31 1 2010-01-15 10 3
2011-01-31 2 2009-09-15 50 1
2011-01-31 3 2010-05-25 20 1
2011-01-31 3 2010-06-01 10 2
2011-01-31 3 2010-09-01 200 3
I want to expand out rows into columns, adding two columns for each row (QTY and START_DATE) so that each date + ID has only one line:
DATE ID SD1 QTY1 SD2 QTY2 SD3 QTY3
2011-01-31 1 2009-04-30 40 2009-10-31 5 2010-01-15 10
2011-01-31 2 2009-09-15 50 NULL NULL NULL NULL
2011-01-31 3 2010-05-25 20 2010-06-01 10 2010-09-01 200
Right now I have up to 44 that I need to add (MAX(ROW)), but in the future there could be more. I can manually add the 44 by doing:
max(CASE WHEN ROW = 1 THEN q.START_DATE END) AS SD1,
SUM(CASE WHEN ROW = 1 THEN q.QTY END) AS QTY1,
max(CASE WHEN ROW = 2 THEN q.START_DATE END) AS SD2,
SUM(CASE WHEN ROW = 2 THEN q.QTY END) AS QTY2,
...
max(CASE WHEN ROW = n THEN q.START_DATE END) AS SDn,
SUM(CASE WHEN ROW = n THEN q.QTY END) AS QTYn
My first question, if I fix the number at say 50, is there a clean way for me to add those 100 columns in my code, or do I just need to explicitly show all 100 lines?
Second question, is there a way for me to use MAX(ROW) to tell the statement how many columns to add? Meaning if MAX(ROW) = 10, add SD1 - SD10 and QTY1 - QTY10. But if on next run MAX(ROW) = 100, add SD1 - SD100, QTY1 - QTY100
Thanks!
I am having trouble with my sum query in SQL Server.
I have a tier price table set up like. The name of the table is called TierPricing.
CID RangeID MinValue MaxValue Price Class
1 1 1 5 1.50 1
2 2 6 10 1.25 1
3 3 11 999999999 1.00 1
.
I have a query of
DECLARE #QuantityEntered int
DECLARE #ClassEntered int
SET #QuantityEntered = 10;
SET #ClassEntered = 1
SELECT IIf(#QuantityEntered>=TierPricing.MaxValue,TierPricing.MaxValue*TierPricing.Price,(#QuantityEntered-(TierPricing.MinValue-1))*TierPricing.Price)) AS RangePrice
FROM
TierPricing
WHERE
(((TierPricing.MinValue)<=#QuantityEntered) AND ((TierPricing.Class)=#ClassEntered));
The problem arises when I use the value of 10 for #QuantityEntered. Instead of returning 13.75 it returns 20.00 and I cant figure out why. From the table from value 9 to 10 should increase by 1.25 from 12.50 to 13.75.
Further Explanation.
#QuantityEntered = 1 returns 1.50 because 1 falls in between 1 and 5 and 1.50 is added from price field for a total of 1.50
#QuantityEntered = 2 returns 3.00 because 2 falls in between 1 and 5 and 1.50 is added from price field for total of 3.00
#QuantityEntered = 3 returns 4.50 because 3 falls in between 1 and 5 and 1.50 is from price field added for total of 4.50
#QuantityEntered = 4 returns 6.00 because 4 falls in between 1 and 5 and 1.50 is from price field added for total of 6.00
#QuantityEntered = 5 returns 7.50 because 5 falls in between 1 and 5 and 1.50 is from price field added for total of 7.50
#QuantityEntered = 6 returns 8.75 because 6 falls in between 6 and 10 and 1.25 is from price field added for total of 8.75
#QuantityEntered = 7 returns 10.00 because 7 falls in between 6 and 10 and 1.25 is from price field added for total of 10.00
#QuantityEntered = 8 returns 11.25 because 8 falls in between 6 and 10 and 1.25 is from price field added for total of 11.25
#QuantityEntered = 9 returns 12.50 because 9 falls in between 6 and 10 and 1.25 is from price field added for total of 12.50
#QuantityEntered = 10 Should return 13.75 but returns 20.00
What I am doing wrong with my query?
I was trying to solve this problem myself when I found your question. I figured out a set based way to get the correct result, but you have to change your Min and Max values to start from 0 and start from the lower tier's end. So the tiers are now 0-5, 5-10, and 10 - 999999999. Here is a recreation of your problem:
create table #TierPricing
(
CID int
,RangeId int
,MinValue int
,MaxValue int
,Price money
,Class int
)
insert into #TierPricing(CID, RangeId, MinValue, MaxValue, Price, Class) values (1,1,0,5,1.50,1)
insert into #TierPricing(CID, RangeId, MinValue, MaxValue, Price, Class) values (2,2,5,10,1.25,1)
insert into #TierPricing(CID, RangeId, MinValue, MaxValue, Price, Class) values (3,3,10,999999999,1.00,1)
DECLARE #QuantityEntered int
DECLARE #ClassEntered int
SET #QuantityEntered = 10;
SET #ClassEntered = 1
;with t as (
select
#TierPricing.*
,case
when #QuantityEntered > MaxValue then MaxValue - MinValue --The #QuantityEntered fills up the entire tier
when #QuantityEntered > MinValue then #QuantityEntered - MinValue --The #QuantityEntered partillay fills the tier
else 0
end as TierQuantity
from #TierPricing
)
select
sum(TierQuantity * Price) as RangePrice
from t
drop table #TierPricing
This will return 13.75 when #QuantityEntered is set to 10.
I have a data.frame like below.
toolid startdate enddate stage
abc 1-Jan-13 5-Jan-13 production
abc 6-Jan-13 10-Jan-13 down
xyz 3-Jan-13 8-Jan-13 production
xyz 9-Jan-13 15-Jan-13 down
I want to get final output which will be like below. The output needs to return - count of each stage (there could be more than 2 stages) over each day between 1jan13 to 15jan13 (or any date range that an user wants). I was able to create the required result in R. I also wrote a cursor in SQL and it achieves the purpose. But is there a way to do the same without using cursors? I am looking for logic and direction.
date down production
1 2013-01-01 0 1
2 2013-01-02 0 1
3 2013-01-03 0 2
4 2013-01-04 0 2
5 2013-01-05 0 2
6 2013-01-06 1 1
7 2013-01-07 1 1
8 2013-01-08 1 1
9 2013-01-09 2 0
10 2013-01-10 2 0
11 2013-01-11 1 0
12 2013-01-12 1 0
13 2013-01-13 1 0
14 2013-01-14 1 0
15 2013-01-15 1 0
I think this may be what you want. It requires a recursive CTE to get a row for each day in the range.
with daterange as (
select startdate=min(startdate),enddate=max(enddate) from #source
), dates as (
select d=(select startdate from daterange) union all
select dateadd(day,1,d) from dates where d<(select enddate from daterange)
)
select
d,
down=(select count(*) from #source where d between startdate and enddate and stage='down'),
production=(select count(*) from #source where d between startdate and enddate and stage='production')
from dates
order by d;