Compare two different column in sql server to get result - sql-server

i'm stuck in problem, i want to get result who's value falls between SlabFrom & Slabto
Query:
Declare #Userinputvalue Decimal(11,6);
Set #Userinputvalue = '700001';
select * from _TaxRate
where SlabTo >= #Userinputvalue and SlabFrom <= #Userinputvalue
TABLE DATA (EXISTING DATA)
SRNO SlabFrom SlabTo Perage
-----------------------------------------
1 0 600000 0
2 600001 1200000 5
3 1200001 1500000 7
4 1500001 2000000 10
Above Result
No Data Found / Blank
But, I Need suppose row number two because my user input value found between (600001 - 1200000), but above query return no data.
Any Help will be highly appreciated.

If you run this code you'll see why
Declare #Userinputvalue Decimal(11,6);
Set #Userinputvalue = '700001';
select #Userinputvalue;
The result is arithmetic overflow. Decimal(11, 6) is not wide enough to store '700001'
Suppose all of the columns are integers, then it works without issues
Data
drop table if exists #tTest;
go
create table #tTest(
SRNO int,
SlabFrom int,
SlabTo int,
Perage int);
insert #tTest(SRNO, SlabFrom, SlabTo, Perage) values
(1, 0, 600000, 0),
(2, 600001, 1200000, 0),
(3, 1200001, 1500000, 0),
(4, 1500001, 2000000, 0);
Query
Declare #Userinputvalue int;
Set #Userinputvalue = 700001;
select *
from #tTest t
where SlabTo >= #Userinputvalue
and SlabFrom <= #Userinputvalue;
Output
SRNO SlabFrom SlabTo Perage
2 600001 1200000 0

Related

In T-SQL is there a built-in command to determine if a number is in a range from another table

This is not a homework question.
I'm trying to take the count of t-shirts in an order and see which price range the shirts fall into, depending on how many have been ordered.
My initial thought (I am brand new at this) was to ask another table if count > 1st price range's maximum, and if so, keep looking until it's not.
printing_range_max printing_price_by_range
15 4
24 3
33 2
So for example here, if the order count is 30 shirts they would be $2 each.
When I'm looking into how to do that, it looks like most people are using BETWEEN or IF and hard-coding the ranges instead of looking in another table. I imagine in a business setting it's best to be able to leave the range in its own table so it can be changed more easily. Is there a good/built-in way to do this or should I just write it in with a BETWEEN command or IF statements?
EDIT:
SQL Server 2014
Let's say we have this table:
DECLARE #priceRanges TABLE(printing_range_max tinyint, printing_price_by_range tinyint);
INSERT #priceRanges VALUES (15, 4), (24, 3), (33, 2);
You can create a table with ranges that represent the correct price. Below is how you would do this in pre-2012 and post-2012 systems:
DECLARE #priceRanges TABLE(printing_range_max tinyint, printing_price_by_range tinyint);
INSERT #priceRanges VALUES (15, 4), (24, 3), (33, 2);
-- post-2012 using LAG
WITH pricerange AS
(
SELECT
printing_range_min = LAG(printing_range_max, 1, 0) OVER (ORDER BY printing_range_max),
printing_range_max,
printing_price_by_range
FROM #priceRanges
)
SELECT * FROM pricerange;
-- pre-2012 using ROW_NUMBER and a self-join
WITH prices AS
(
SELECT
rn = ROW_NUMBER() OVER (ORDER BY printing_range_max),
printing_range_max,
printing_price_by_range
FROM #priceRanges
),
pricerange As
(
SELECT
printing_range_min = ISNULL(p2.printing_range_max, 0),
printing_range_max = p1.printing_range_max,
p1.printing_price_by_range
FROM prices p1
LEFT JOIN prices p2 ON p1.rn = p2.rn+1
)
SELECT * FROM pricerange;
Both queries return:
printing_range_min printing_range_max printing_price_by_range
------------------ ------------------ -----------------------
0 15 4
15 24 3
24 33 2
Now that you have that you can use BETWEEN for your join. Here's the full solution:
-- Sample data
DECLARE #priceRanges TABLE
(
printing_range_max tinyint,
printing_price_by_range tinyint
-- if you're on 2014+
,INDEX ix_xxx NONCLUSTERED(printing_range_max, printing_price_by_range)
-- note: second column should be an INCLUDE but not supported in table variables
);
DECLARE #orders TABLE
(
orderid int identity,
ordercount int
-- if you're on 2014+
,INDEX ix_xxy NONCLUSTERED(orderid, ordercount)
-- note: second column should be an INCLUDE but not supported in table variables
);
INSERT #priceRanges VALUES (15, 4), (24, 3), (33, 2);
INSERT #orders(ordercount) VALUES (10), (20), (25), (30);
-- Solution:
WITH pricerange AS
(
SELECT
printing_range_min = LAG(printing_range_max, 1, 0) OVER (ORDER BY printing_range_max),
printing_range_max,
printing_price_by_range
FROM #priceRanges
)
SELECT
o.orderid,
o.ordercount,
--p.printing_range_min,
--p.printing_range_max
p.printing_price_by_range
FROM pricerange p
JOIN #orders o ON o.ordercount BETWEEN printing_range_min AND printing_range_max
Results:
orderid ordercount printing_price_by_range
----------- ----------- -----------------------
1 10 4
2 20 3
3 25 2
4 30 2
Now that we have that we can

Accessing prior rows and divide its value by current row

I have the rows below, and i want to access prior row and divide its value by current row. For every row, i need to calculate the Vi value, this Vi value is equal to Vi-1/Vi which means that:
Given the table
Table T
id value out
1 100
2 200
3 10
4 50
I want to generate these values
V1 = 100
V2= 100/200 = 0.5
V3 = 0.5/10 = 0.05
V4 = 0.05/50 = 0.001
So at the end i want the following output:
id value out
1 100 100
2 200 0.5
3 10 0.05
4 50 0.001
I tried using the aggregate function SUM with OVER(), but i do not know how to solve this problem as i need to divide and not sum the value
SELECT id, value, SUM(value) OVER(ORDER BY id ROWS BETWEEN
1 PRECEDING AND 1 PRECEDING ) / value as out
FROM T
Sample data:
CREATE TABLE t(
id INT,
value INT
);
INSERT INTO t VALUES
(1, 100), (2, 200), (3, 10), (4, 50);
Unfortunately, SQL do not have Product, but it should be simple to use cte. The performance should be not bad if id was indexed
DECLARE #T table (id int identity(1,1) primary key, value int)
INSERT #T VALUES (100), (200), (10), (50)
;WITH cte AS
(
SELECT id, value, CAST(value AS decimal(20,4)) AS out FROM #T WHERE id = 1
UNION ALL SELECT T.id, T.value, CAST(cte.out / T.value AS decimal(20,4)) FROM cte INNER JOIN #T T ON cte.id = T.id - 1
)
SELECT * FROM cte

SQL Server: How to write a query to select id having all values less than 0(zero)

Consider the following table,
Table 1:
id (int): 1 1 2 2 2
value (int): -1 0 -1 -3 -8
How to write a query to select the id from the table which has all the values of column value less than 0?
Try this one -
DECLARE #temp TABLE
(
id INT,
value INT
)
INSERT INTO #temp (id, value)
VALUES (1, -1), (1, 0), (2, -1), (2, -3), (2, -8)
SELECT id
FROM #temp
GROUP BY id
HAVING MAX(value) < 0
Output -
id
-----------
2

Using UDF in SELECT statement

I made a user-define function for business hours calculation.
This is my UDF.
CREATE FUNCTION fn_GetBusinessHour (#date datetime, #addHours int)
RETURNS datetime
AS
BEGIN
DECLARE #CalcuatedDate datetime;
DECLARE #addDayCount int, #addHourCount int, #addMinCount int;
SET #addDayCount = #addHours / 8.5;
SET #addHourCount = #addHours - (#addDayCount * 8.5);
SET #addMinCount = #addHours - (#addDayCount * 8.5) - #addHourCount;
IF(#addDayCount != 0)
SET #CalcuatedDate = DATEADD(DD, #addDayCount, #date);
SET #CalcuatedDate = DATEADD(HH, #addHourCount, #CalcuatedDate);
IF(#addMinCount != 0)
SET #CalcuatedDate = DATEADD(MM, #addMinCount, #CalcuatedDate);
RETURN #CalcuatedDate;
END
When I test using following statement,
SELECT dbo.fn_GetBusinessHour(GETDATE(), 40)
It shows proper result.
However, I use my function like this,
SELECT TicketID
, DateTimeLogged --Type: Datetime
, Priority --Type: int
, [dbo].[fn_GetBusinessHour](DateTimeLogged, Priority)
FROM TicketHeader
the result shows only NULL value.
TicketID DateTimeLogged Priority (No column name)
1 2011-07-04 11:26:19.510 30 NULL
2 2011-07-04 13:58:45.683 30 NULL
3 2011-07-05 10:09:16.923 10 NULL
4 2011-07-05 13:13:30.237 30 NULL
5 2011-07-05 16:50:34.033 20 NULL
I tried CONVERT because it worked when I give a value 40 but it also shows null values.
SELECT TicketID
, DateTimeLogged --Type: Datetime
, Priority --Type: int
, [dbo].[fn_GetBusinessHour](DateTimeLogged, CONVERT(int, Priority))
FROM TicketHeader
How can I fix this to work my UDF?
Why this thing happen?
I cannot understand what is different between Priority and 40.
Thank you in advance.
For values of priority > 8.5, this seems to work fine for me:
DECLARE #t TABLE(TicketID INT, DateTImeLogged DATETIME, Priority INT);
INSERT #t SELECT 1,'20110704 11:26:19.510',30
UNION ALL SELECT 2,'20110704 13:58:45.683',30
UNION ALL SELECT 3,'20110705 10:09:16.923',10
UNION ALL SELECT 4,'20110705 13:13:30.237',30
UNION ALL SELECT 5,'20110705 16:50:34.033',20;
SELECT TicketID
, DateTimeLogged --Type: Datetime
, Priority --Type: int
, [dbo].[fn_GetBusinessHour](DateTimeLogged, Priority)
FROM #t;
Yields:
TicketID DateTimeLogged Priority (No column name)
-------- ----------------------- -------- -----------------------
1 2011-07-04 11:26:19.510 30 2011-07-07 15:26:19.510
2 2011-07-04 13:58:45.683 30 2011-07-07 17:58:45.683
3 2011-07-05 10:09:16.923 10 2011-07-06 11:09:16.923
4 2011-07-05 13:13:30.237 30 2011-07-08 17:13:30.237
5 2011-07-05 16:50:34.033 20 2011-07-07 19:50:34.033
If I add another row with a Priority < 8.5, e.g.:
INSERT #t SELECT 6,'20110705 13:13:30.237',5;
Then this row is added to the result:
TicketID DateTimeLogged Priority (No column name)
-------- ----------------------- -------- -----------------------
6 2011-07-05 13:13:30.237 5 NULL
In other words, the function will output NULL if the function logic leaves #CalculatedDate unassigned, which will happen if #addDayCount = 0. In the function you say:
IF(#addDayCount != 0)
SET #CalcuatedDate = DATEADD(DD, #addDayCount, #date);
Since #addDayCount is an INT, try this:
DECLARE #addDayCount INT;
SET #addDayCount = 5 / 8.5;
SELECT #addDayCount;
Result:
0
So because #CalculatedDate isn't assigned a value initially, all of the following DATEADD operations are performing DATEADD(interval, number, NULL) which still yields NULL.
So perhaps you need to use a different data type for the variables in the function...

T-SQL - Filling in the gaps in running balance

I am working on a Data Warehouse project and the client provides daily sales data. On-hand quantities are provided in most lines but are often missing. I need help on how to fill those missing values based on prior OH and sales information.
Here's a sample data:
Line# Store Item OnHand SalesUnits DateKey
-----------------------------------------------
1 001 A 100 20 1
2 001 A 80 10 2
3 001 A null 30 3 --[OH updated with 70 (80-10)]
4 001 A null 5 4 --[OH updated with 40 (70-30)]
5 001 A 150 10 5 --[OH untouched]
6 001 B null 4 1 --[OH untouched - new item]
7 001 B 80 12 2
8 001 B null 10 3 --[OH updated with 68 (80-12]
Lines 1 and 2 are not to be updated because OnHand quantities exist.
Lines 3 and 4 are to be updated based on their preceding rows.
Line 5 is to be left untouched because OnHand is provided.
Line 6 is to be left untouched because it is the first row for Item B
Is there a way I can do this in a set operation? I know I can do it easily using a fast_forward cursor but it will take a long time (15M+ rows).
Thanks for your help!
Test data:
declare #t table(
Line# int, Store char(3), Item char, OnHand int, SalesUnits int, DateKey int
)
insert #t values
(1, '001', 'A', 100, 20, 1),
(2, '001', 'A', 80 , 10, 2),
(3, '001', 'A', null, 30, 3),
(4, '001', 'A', null, 5, 4),
(5, '001', 'A', 150, 10, 5),
(6, '001', 'B', null, 4, 1),
(7, '001', 'B', null, 4, 2),
(8, '001', 'B', 80, 12, 3),
(9, '001', 'B', null, 10, 4)
Script to populate not using cursor:
;with a as
(
select Line#, Store, Item, OnHand, SalesUnits, DateKey, 1 correctdata from #t where DateKey = 1
union all
select t.Line#, t.Store, t.Item, coalesce(t.OnHand, a.onhand - a.salesunits), t.SalesUnits, t.DateKey, t.OnHand from #t t
join a on a.DateKey = t.datekey - 1 and a.item = t.item and a.store = t.store
)
update t
set OnHand = a.onhand
from #t t join a on a.line# = t.line#
where a.correctdata is null
Script to populate using cursor:
declare #datekey int, #store int, #item char, #Onhand int,
#calculatedonhand int, #salesunits int, #laststore int, #lastitem char
DECLARE sales_cursor
CURSOR FOR
SELECT datekey+1, store, item, OnHand -SalesUnits, salesunits
FROM #t sales
order by store, item, datekey
OPEN sales_cursor;
FETCH NEXT FROM sales_cursor
INTO #datekey, #store, #item, #Onhand, #salesunits
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT #calculatedonhand = case when #laststore = #store and #lastitem = #item
then coalesce(#onhand, #calculatedonhand - #salesunits) else null end
,#laststore = #store, #lastitem = #item
UPDATE s
SET onhand=#calculatedonhand
FROM #t s
WHERE datekey = #datekey and #store = store and #item = item
and onhand is null and #calculatedonhand is not null
FETCH NEXT FROM sales_cursor
INTO #datekey, #store, #item, #Onhand, #salesunits
END
CLOSE sales_cursor;
DEALLOCATE sales_cursor;
I recommand you use the cursor version, I doubt you can get a decent performance using the recursive query. I know people in here hate cursors, but when your table has that size, it can be the only solution.

Resources