How to Implement Excel COMBIN function in SQL - sql

How can i implement Excel COMBIN function in SQL 2005, either in a store procedure or in a function. About COMBIN function in Excel follow this Link.
Thanks.

Either implement a factorial function or depending on your possible input range, store factorial results in a table.
Implement the formula, as seen in your link.

No built-in method for doing this, you will have to make a custom user-defined function.
Rather than doing something crazy like a recursively factorial (as seen in this forum discussion), I would do the following:
Create a factorial lookup table, holding pre-calculated factorial values (maybe 1! to 100!, since 100! is over 9.3 × 10^157), or as high as you think you might need.
Then in your user-defined function, just look up n!, k!, and (n-k)! from the table, then calculate (n!) / (k!) * (n-k)!

Depending on what your possible input values are going to be, it may be worth pre-computing the values and storing them in a table; retrieving COMBIN(n, k) would then be as easy as
SELECT value FROM Combin WHERE n = #n AND k = #k

Precalculation does seem more sensible but a solution without.
declare #n int
declare #k int
SET #n = 8
SET #k = 2
SELECT
POWER(10.0, SUM(CASE WHEN Number > (#n - #k) THEN LOG10(Number) ELSE 0 END))/
POWER(10.0, SUM(CASE WHEN Number <= #k THEN LOG10(Number) ELSE 0 END))
FROM master.dbo.spt_values
WHERE type='P' AND
((Number > 0 and Number <= #k) OR (Number > (#n - #k) AND Number <= #n))

Related

SQL order of operation does not make sense with simple mathematical calculation

I have a simple calculation to do in a stored procedure. Depending on the order I put the variables I get a different result
If you copy/past this into SQL Query Analyzer you can easily reproduce the issue where I get a different result. The result I was looking for was the second calculation (57364.32)
DECLARE #mnyDocTotal MONEY;
DECLARE #mnyUSDTotal MONEY
DECLARE #mnyDetailLine MONEY
SET #mnyDocTotal = 78000
SET #mnyUSDTotal = 86046.48
SET #mnyDetailLine = 52000
PRINT 'Result: ' + CAST(ROUND(#mnyDetailLine / #mnyDocTotal * #mnyUSDTotal,2) as char(20))
PRINT 'Result: ' + CAST(ROUND(#mnyDetailLine * #mnyUSDTotal / #mnyDocTotal,2) as char(20))
--Result: 57358.58
--Result: 57364.32
I believe that / and * are on the same level and operate from left to right in this case.
If you run the numbers with a calculator, you will always get 57364.32.
This caused me about 2 hours of effort to figure this out. In all my years I've never had this issue occur. Why is the result different?
This article does a pretty good job explaining why you should not use money.
They are not numeric values. They are stored as integers. And they have rounding problems. So:
(a * b) / c
can product a different result due to rounding from:
(a / c) * b
This is actually true of integers in general, as this simple example illustrates:
select (2 * 4 / 3), (2 / 3 * 4)
If you use numeric, you won't have a problem. Here is a db<>fiddle.

Find next greater number with zeros in sql number

I'm looking for a way to find next greater number starting by 1 and followed by zeros in Microsoft SQL. Numbers could vary in digits. ie:
Query: 9856, Result after procedure: 10000
Query: 98999, Result after procedure: 100000
Thanks.
EDIT: There is no chance of having negative numbers. This is a calculation for a energy meter. For example, numbers can go up to 99999 or 999999 or 9999999. When energy overcome that number, it will start again at 0. So I can't read what energy has been used in that period. To know it, I need to calculate the number as asked, then perform some basic maths.
There is no need for knowing what is going on on 10, 100, etc, because of the nature of the operation. It will only be used when the above escenario happend.
I don't know why you require or mathematically any other formula can be implemented. but technically that can be achieved as follows
DECLARE #count INT
SET #count = 1000
DECLARE #result INT
SET #result = CASE WHEN #count%10 = 0 THEN #count ELSE CAST('1'+REPLICATE('0',LEN(#count)) AS INT) end
SELECT #result
This works for positive numbers (numbers greater than zero):
select power(10, ceiling( log10(the_number) )) from mytable;
In case the number is already a power of ten (1, 10, 100, ...) , the number itself is returned.
You can do this with just arithmetic operations:
select power(10, floor(log(v.n - 0.1, 10)) + 1)
from (values (1), (10), (8), (9982), (124)) v(n)
This is a fairly crude way of doing it, however it does work. The query basically looks at the number of digits your number has, assumes the next integer you want starts with a 1 and then adds the relevant number of 0's to it.
Note this only looks for the next increment and does not round down.
Also for 10 you will get 100 and for 1000 you will get 10000.
declare #number int = 98999;
declare #len int = len(#number);
declare #stringtoreturn nvarchar(200)='1';
declare #runs int = 1;
while #runs<=#len
begin
select #stringtoreturn = #stringtoreturn + '0';
select #runs=#runs+1;
end
select #stringtoreturn;

how to sum up value within one cell SQL

I have some binary values such as 00, 0000, 001000.11111000, 1111100000
I need to sum it up so it turns into 0, 0, 1, 5, 5 ( sum 0s and 1s up)
how can we do that in SQL please?
Thanks
Assumption:
The binary values are stored as string.
Each value is in its own cell in a table. Something like:
BinaryValues (Consider it a column name)
00
0000
001000
and so on.
You want to add up the individual digits to get the sum.
SQL Product you are usind supports functions, looping, string manipulation like substring, extracting string length etc.
As per my best knowledge these are primitives available in all SQL products.
Solution:
Write a function (call it by any name. Ex: AddBinaryDigits) which will take the binary value in string format as input.
Inside the function and do a string manipulation. Extract each digit and add it up. Return the sum as result.
Call the function:
If using binary values stored in a table:
SELECT AddBinaryDigits(BinaryValues) FROM <WhatEverTableName>
If using fixed value:
SELECT AddBinaryDigits('00')
SELECT AddBinaryDigits('0000')
SELECT AddBinaryDigits('001000')
and so on.
Edited to include the request to create function.
CREATE FUNCTION <funtionName>
(
#ParameterName AS VARCHAR(expected string length like 10/15/20 etc.)
)
RETURNS INT
BEGIN
SQL Code to sum
RETURN SummedUpValue
END
Use the below query. If needed convert it into function.
create function dbo.fnSumChars(#someInt VARCHAR(20))
RETURNS INT
AS
BEGIN
DECLARE #count INT = LEN(#someInt),
#counter INT = 1
DECLARE #Sum INT = 0
WHILE #counter <= #count
BEGIN
SELECT #sum += CAST(SUBSTRING(CAST(#someInt AS VARCHAR), #counter, 1) AS int)
SELECT #counter += 1
END
RETURN #sum --5
END
This is the function and you can call this function like below
SELECT dbo.fnSumChars('1111100000')
If these are already in string format, this is the easiest:
select len(replace('1111100000', '0', ''))
No need for a function either, because it can be inlined in the query. Functions, even the light ones, incure perf penalty.

SQL: how to get the left 3 numbers from an int

I want to retrieve the left 3 numbers from an integer to be stored in a table. For example, if the int is 1234567, I want to retrieve 123. I want the second number (123) to also be an int; I don't want to convert anything to a string.
(And yes, really I should be working with strings. But I don't have control over that aspect of the issue.)
Thank you!
For SQL Server, the easiest way would definitely be:
SELECT CAST(LEFT(CAST(YourInt AS VARCHAR(100)), 3) AS INT)
Convert to string, take the left most three characters, and convert those back to an INT.
Doing it purely on the numerical value gets messy since you need to know how many digits you need to get rid of and so forth...
If you want to use purely only INT's, you'd have to construct something like this (at least you could do this in SQL Server - I'm not familiar enough with Access to know if that'll work in the Access SQL "dialect"):
DECLARE #MyInt INT = 1234567
SELECT
CASE
WHEN #MyInt < 1000 THEN #MyInt
WHEN #MyInt > 10000000 THEN #MyInt / 100000
WHEN #MyInt > 1000000 THEN #MyInt / 10000
WHEN #MyInt > 100000 THEN #MyInt / 1000
WHEN #MyInt > 10000 THEN #MyInt / 100
WHEN #MyInt > 1000 THEN #MyInt / 10
END AS 'NewInt'
But that's always an approximation - what if you have a really really really large number..... it might just fall through the cracks....
Without casting to string, how about this?
(T-SQL)
select #i / power(10,floor(log10(#i))-2)
Throws an error if the int is less than 100, but seems to work otherwise.
EDIT: To handle the error gracefully, you'd have to use a CASE since TSQL has no GREATEST() function...
select #i / case when #i < 100 then 1 else power(10,floor(log10(#i))-2) end
In access SELECT clng(left(cstr(field), 3)) FROM T should work.
Edit: Infact I bet it wont care about the cstr().
;WITH c10 AS
(
SELECT
Number
FROM
MyTable --?? WHERE Number>=1000
UNION ALL
SELECT Number/10 FROM c10 WHERE Number>=1000
)
SELECT Number FROM c10 WHERE Number < 1000
I can't test this, but it should do the trick. Iterate through until you end up with < 1000, relying on integer division. You may need to filter on the first clause to fine tune it
For a raw TSQL SQL Server 2005 solution only
well if you have access to php you could use substr
echo substr('1234567', 0, 3); and then convert the string back to an int
Converting an integer to a string in PHP
good luck!

SQL query--String Permutations

I am trying to create a query using a db on OpenOffice where a string is entered in the query, and all permutations of the string are searched in the database and the matches are displayed. My database has fields for a word and its definition, so if I am looking for GOOD I will get its definition as well as the definition for DOG.
You'll need a third column as well. In this column you'll have the word - but with the letters sorted in alphabetical order. For example, you'll have the word APPLE and in the next column the word AELPP.
You would sort the word your looking for - and run a some SQL code like
WHERE sorted_words = 'my_sorted_word'
for the word apple, you would get something like this:
unsorted sorted
AELPP APPLE
AELPP PEPLA
AELPP APPEL
Now, you also wanted - correct me if I'm wrong, but you want all the words that can be made with **any combination ** of the letters, meaning APPLE also returns words like LEAP and PEA.
To do this, you would have to use some programming language - you would have to write a function that preformed the above recursively, for example - for the word AELLP you have
ELLP
ALLP
AELP
and so forth.. (each time subtracting one letter in every combination, and then two letters in every combination possible ect..)
Basically, you can't easily do permutations in single SQL statement. You can easily do them in another language though, for example here's how to do it in C#: http://msdn.microsoft.com/en-us/magazine/cc163513.aspx
Ok, corrected version that I think handles all situations. This will work in MS SQL Server, so you may need to adjust it for your RDBMS as far as using the local table and the REPLICATE function. It assumes a passed parameter called #search_string. Also, since it's using VARCHAR instead of NVARCHAR, if you're using extended characters be sure to change that.
One last point that I'm just thinking of now... it will allow duplication of letters. For example, "GOOD" would find "DODO" even though there is only one "D" in "GOOD". It will NOT find words of greater length than your original word though. In other words, while it would find "DODO", it wouldn't find "DODODO". Maybe this will give you a starting point to work from though depending on your exact requirements.
DECLARE #search_table TABLE (search_string VARCHAR(4000))
DECLARE #i INT
SET #i = 1
WHILE (#i <= LEN(#search_string))
BEGIN
INSERT INTO #search_table (search_string)
VALUES (REPLICATE('[' + #search_string + ']', #i)
SET #i = #i + 1
END
SELECT
word,
definition
FROM
My_Words
INNER JOIN #search_table ST ON W.word LIKE ST.search_string
The original query before my edit, just to have it here:
SELECT
word,
definition
FROM
My_Words
WHERE
word LIKE REPLICATE('[' + #search_string + ']', LEN(#search_string))
maybe this can help:
Suppose you have a auxiliary Numbers table with integer numbers.
DECLARE #s VARCHAR(5);
SET #s = 'ABCDE';
WITH Subsets AS (
SELECT CAST(SUBSTRING(#s, Number, 1) AS VARCHAR(5)) AS Token,
CAST('.'+CAST(Number AS CHAR(1))+'.' AS VARCHAR(11)) AS Permutation,
CAST(1 AS INT) AS Iteration
FROM dbo.Numbers WHERE Number BETWEEN 1 AND 5
UNION ALL
SELECT CAST(Token+SUBSTRING(#s, Number, 1) AS VARCHAR(5)) AS Token,
CAST(Permutation+CAST(Number AS CHAR(1))+'.' AS VARCHAR(11)) AS
Permutation,
s.Iteration + 1 AS Iteration
FROM Subsets s JOIN dbo.Numbers n ON s.Permutation NOT LIKE
'%.'+CAST(Number AS CHAR(1))+'.%' AND s.Iteration < 5 AND Number
BETWEEN 1 AND 5
--AND s.Iteration = (SELECT MAX(Iteration) FROM Subsets)
)
SELECT * FROM Subsets
WHERE Iteration = 5
ORDER BY Permutation
Token Permutation Iteration
----- ----------- -----------
ABCDE .1.2.3.4.5. 5
ABCED .1.2.3.5.4. 5
ABDCE .1.2.4.3.5. 5
(snip)
EDBCA .5.4.2.3.1. 5
EDCAB .5.4.3.1.2. 5
EDCBA .5.4.3.2.1. 5
(120 row(s) affected)