Count total balls from cricket overs and sum overs (mssql) - sql-server

I'm creating a stored procedure in SQL Server for a cricket application. How can I find the total number of balls, given there are 6 balls in an over.
Suppose there are 4 overs. We can easily calculate 4 * 6. But what if there were 4.5 overs? I also want to sum the two different cricket matches over of a particular bowler over.
For example:
match1 overs 4.5
match2 overs 6.3
addition should be 11.2
With a calculator we get 10.8
Here is what I tried
COALESCE(Sum(Overs),0) * 6 + (COALESCE(Sum(Overs),0) - COALESCE(Sum(Overs),0))* 10 as Totalballs,

Based on your last comment, we can first FLOOR the over to find what the first multiple will be.
Then we subtract the over from that, convert to INT, and add.
declare #over decimal(4,1) = 4.5
select
SixeTimesThis = floor(#over)
,Remainder = (#over - floor(#over))
,RemainderAsInt = cast(replace((#over - floor(#over)),'.','') as int)
,FinalResult = floor(#over) * 6 +cast(replace((#over - floor(#over)),'.','') as int)

You can use modulus % to get the extra balls.
Example snippet:
select *, coalesce(floor(Overs)*6 + floor((Overs%1)*10), 0) as Balls
from (values
(1.0),
(4.0),
(4.5),
(null)
) as v(Overs);
Test on db<>fiddle here
Result:
Overs Balls
----- -----
1.0 6
4.0 24
4.5 29
NULL 0

Related

Query min column header while excluding blanks and handling duplicates

I have the following table.
Name
Score A
Score B
Score C
Bob
8
6
Sue
9
12
9
Joe
11
2
Susan
7
9
10
Tim
10
12
4
Ellie
9
8
7
In my actual table there are about 2k rows.
I am trying to get the min score (excluding blanks & handles duplicate scores) for each person into another column using the QUERY formula or ARRAYFORMULA, really to avoid entering a formula for each row.
As I do currently have this
=INDEX($B$1:$D$1,MATCH(MIN(B2:D2),B2:D2,0))
But that involves dragging down through each cell, as I do this on a few sheets that have circa 2k rows, it's very slow when inputting new data.
This should be the end result
Name
Score A
Score B
Score C
Min Score
Bob
8
6
Score C
Sue
9
12
9
Score A
Joe
11
2
Score B
Susan
7
9
10
Score A
Tim
10
12
4
Score C
Ellie
9
8
7
Score C
use:
=INDEX(SORTN(SORT(SPLIT(QUERY(FLATTEN(
IF(B2:D="",,B1:D1&"Γ—"&B2:D&"Γ—"&ROW(B2:D))),
"where Col1 is not null", ),
"Γ—"), 3, 1, 2, 1), 9^9, 2, 3, 1),, 1)
The following answer employs three of the newest set of functions that are still being rolled out by Google so you might not be able to use it right now, but in a few weeks when they're fully rolled out you definitely will (this worked using the Android version of Sheets just now for me):
=arrayformula(if(len(A2:A),byrow(B2:D,lambda(row,xlookup(min(row),row,B1:D1))),))
Assuming the names are in column A, this should give a result for every row which has a name in it. I'm sure there are other ways of doing this, but these 'row/column-wise' problems are really ideal use-cases for LAMBDA and its helper functions like BYROW.

MS Excel - SumProduct formula with Loop

I have 4 arrays of data where I need a some product but with few conditions.
I'm unable to solve that and I'm not good at creating VBA functions as well.
Can anyone please help?
Apologies for the lack of clarity.
I'll try to give more details here. Please refer the below workbook.
https://drive.google.com/file/d/1XVEe4Sjw6ZeAh-7jyeLDs7Tp5RRQD20i/view?usp=sharing
Investment value is Row 2 * Row 3.
This value is carried across all the months after amortization given in row 4. 5th row is converting the yearly value into monthly value (1/12).
So, in the first month 50 is invested and the value at the beginning of the month after amort of 100%, So 50 is available for month 1. This is further converted into monthly values with the help of row 5. So, the result for month 1 will be 100 * 50% * 100% * 8.33% = 4.1667 [Cell I9]
For the month 2, the value available is,
Value carried from month 1 after amort (100 * 50% * 99%) +
New amount in month 2 (102 * 50% * 100%)
The above value is converted into the monthly value again with the help of row 5.
Result for month 2 => Cell I10 = (100 * 50% * 99% * 8.33%) + (102 * 50% * 100% * 8.33%) = 8.375
Similarly, for month 3 the value will be,
Month 1's investment (100*50%*98%*8.33%) +
Month 2's investment (102*50%*99%*8.33%) +
Month 3's investment (104*50%*100%*8.33%)
I need the above calculation to happen in single cell for all the months. I tried sumproduct with offset. But I couldn't.
REVISED (based upon comment 'all values are dynamic)...
Plug this into cell b6 per screenshot, drag to right:
=SUM($B2:B2*$B3:B3*$B4:B4*$B5:B5)
This will evaluate the sums you have indicated below the 24 month table [at top your linked spreadsheet] i.e. which correspond to respective months 1,2,... etc.
PREVIOUS SOLN:
HIGH LEVEL
Let cell A1 contain the month (=π‘Ÿ, π‘Ÿ πœ– β„•). Plug this into excel to get the sum of the π‘Ÿ terms for k = 1,...,π‘Ÿ:
=A1*(98-A1+(3/2)*(1+A1)+(1/50)*((1+A1)*((2*A1+1)/6-A1/2-1/2)+A1))/24
DERIVATION
Your sequence has π‘Ÿ terms; let 𝑑(π‘˜) be the π‘˜th such term:
𝑑(π‘˜) = (100+2(π‘˜βˆ’1))(1βˆ’(π‘Ÿβˆ’π‘˜)/100)/24
where 1 < 2 < ,..., ≀ π‘˜ ≀ ,.., π‘Ÿ. Let 𝑆(π‘Ÿ) be the sum over π‘˜ = 1, ... , π‘Ÿ. It immediately follows that:
𝑆(π‘Ÿ)= (1/24) βˆ‘(100+2(π‘˜βˆ’1))(1βˆ’(π‘Ÿβˆ’π‘˜)/100); π‘Ÿ πœ– β„•; π‘˜ = 1,2,..,π‘Ÿ
Elementary simplification yields the following:
𝑆(π‘Ÿ) = (1/24) π‘Ÿ { 98 - π‘Ÿ + 1.5 (1 + π‘Ÿ) + 0.02 {(1+π‘Ÿ)((2π‘Ÿ+1)/6 - π‘Ÿ/2 - 1/2) +r } }
(𝑄𝐸𝐷 ☻)
CHECKS
π‘Ÿ (A1)
Result
Status
1
4.17
√
2
8.38
√
3
12.62
√
4
16.91
√
5
21.24
√
..
..
n/a
24
109.81
√

Autoincrement value

I'm working on a local project and I would like to setup a column in a SQL Server table that I called serial. This value should have the next format/validation [A-Z0-9][A-Z0-9][A-Z0-9][A-Z0-9]. Four characters that will have numbers or capital letters.
For example, the first record would be AAA0, and then start incrementing from right to left, but the interesting part is that once it reaches AAA9, I want to continue but with letters, so once 9 is reached, continue with A: AAAA. My last combination would be AAAZ, and then continue with the second position and so on, until I could complete ZZZZ.
Serial
------
AAA0
…
AAAZ
AAB0
…
AABZ
AAC0
…
AACZ
…
ZZZZ
I've been able to do something similar, but for example only incrementing numbers 0000 until 9999 or with just letters AAAA to ZZZZ (see below dummy data).
Please let me know if you have any comments or if you have seen this scenario before. I will appreciate any help.
I've reviewed some data on the internet and did this small test, but once again, this is changing letters.
CREATE TABLE #MyTable
(
MyHeadID INT IDENTITY(0,1) NOT NULL,
Consecutive AS
CHAR(MyHeadID/17576%26+65) + --26^3
CHAR(MyHeadID/676%26+65) + --26^2
CHAR(MyHeadID/26%26+65) + --26^1
CHAR(MyHeadID%26+65) --26^0
PERSISTED NOT NULL,
UniqueID VARCHAR(36) NOT NULL,
CreatedDate datetime DEFAULT GETDATE()
)
INSERT INTO #MyTable (UniqueID)
(SELECT NEWID())
SELECT Consecutive FROM #MyTable
Let's not talk about the UniqueID and CreatedDate columns, those are just for testing purposes. I created an identity column and then the code for the autoincrement on letters.
I also found this reply here but it's not my case since in that reply they are dividing 4 letters and 4 numbers with a substring it can be resolved. In my case, I need to intercalculate numbers and letters from right to left.
Here's a possible solution, counting in base 36 AAA0 starts at decimial 479879.
Ideally you'd have an identity incrementing number on your table starting at 479879. Simulating that with a numbers table generated using a CTE, the following gives base36 counting:
with numbers as (
select 479879 + Row_Number() over (order by a.object_id)n
from sys.all_objects a cross join sys.all_objects b
)
select top 10000
Concat(Char(((n/36/36/36) % 36) + case when (n/36/36/36) % 36 between 0 and 9 then 48 else 55 end),
Char(((n/36/36) % 36) + case when (n/36/36) % 36 between 0 and 9 then 48 else 55 end),
Char(((n/36) % 36) + case when (n/36) % 36 between 0 and 9 then 48 else 55 end),
Char((n % 36) + case when n % 36 between 0 and 9 then 48 else 55 end)) Base36
from numbers
order by n
See Fiddle
The previous answer is good but you can do this and cover all numbers with simple math. Also, let's assume your IDENTITY starts at one. There are 36 values for each digit, so those are base 36 encoded as pointed out. The encoding goes 0 - 9 then A - Z as you mentioned in your post. The get the individual digits of some number n from right to left, the algorithm goes:
n mod 36 is the right most digit.
n / 36 mod 36 gives the second-to-right digit.
n / (36 * 36) mod 36 gives the second-to-left digit.
n / (36 * 36 * 36) mod 36 gives left digit.
To test this logic, we can write a function:
CREATE FUNCTION CustomNumber(#id INT)
RETURNS CHAR(4)
AS BEGIN
RETURN CHAR((#id-1)/ POWER(36, 3)% 36+CASE WHEN (#id-1)/ POWER(36, 3)% 36 BETWEEN 0 AND 9 THEN 48 ELSE 55 END)
+CHAR((#id-1)/ POWER(36, 2)% 36+CASE WHEN (#id-1)/ POWER(36, 2)% 36 BETWEEN 0 AND 9 THEN 48 ELSE 55 END)
+CHAR((#id-1)/ 36% 36+CASE WHEN (#id-1)/ 36% 36 BETWEEN 0 AND 9 THEN 48 ELSE 55 END)
+CHAR((#id-1)% 36+CASE WHEN (#id-1)% 36 BETWEEN 0 AND 9 THEN 48 ELSE 55 END);
END;
We can then test this function by calling it to make sure it works. To call it, lets create some numbers. This is complete overkill, but let's pass it 1 through 1,000,000 so we can see it in action:
;WITH digits (I)
AS (
SELECT I
FROM (VALUES (0), (1),(2),(3),(4),(5),(6),(7),(8),(9)) AS digits (I) ),
integers (I)
AS (SELECT D1.I + (10 * D2.I) + (100 * D3.I) + (1000 * D4.I) + (10000*D5.I) + (100000*D6.I)
FROM digits AS D1
CROSS JOIN digits AS D2
CROSS JOIN digits AS D3
CROSS JOIN digits AS D4
CROSS JOIN digits AS D5 CROSS JOIN digits AS D6
)
SELECT I, dbo.CustomNumber(I)
FROM integers
WHERE I > 0
ORDER BY I;
If you run that and patiently wait (it takes about 20 seconds on my weak laptop, but you don't have to use a million numbers if you don't like) you will see that it does produce the result that you want. At this point we know the formula is correct, so you have options to add it to your table.
One option is to use the formula as a PERSISTED column as you did. Another option is to use a trigger. You can leave the formula as a function or you can just put the code in directly. If you need more characters than 4, you can easily add another by following the pattern (just change the POWER to which you raise).
As I mentioned, the previous answer is good, I just wanted to show another method and its derivation. I have had to implement custom sequences several times with varying formats and you can use this general technique.

SQL Server query problem. example is in excel sheet picture

Please see the following pic and i want to convert this formula in SQL Server.
in excel sheet
M N
15 1 0
16 3 1
17 5 2
18 8 4
19 9 4
N= IF(M16-M15<=1,N15,M16-M15-1+N15
Please see the screenshot for reference:
As per your tags, this can be done with LAG and then doing a running total.
For each row, first calculate the difference in M from the previous row (using LAG) - I call this Dif_Last_M. This mirrors the 'M24-M23' part of your formula.
If Dif_Last_M is <= 1, add 0 to the running total (effectively making the running total the same as for the previous row)
Else if Dif_Last_M is > 1, add (Dif_Last_M minus 1) to the running total
Here is the code assuming your source table is called #Temp and has an ID (sorting value)
WITH M_info AS
(SELECT ID, M, (M - LAG(M, 1) OVER (ORDER BY ID)) AS Dif_Last_M
FROM #Temp
)
SELECT ID,
M,
SUM(CASE WHEN Dif_Last_M > 1 THEN Dif_Last_M - 1 ELSE 0 END) OVER (ORDER BY ID) AS N
FROM M_info;
And here are the results
ID M N
1 1 0
2 3 1
3 5 2
4 8 4
5 9 4
6 12 6
7 13 6
Here is a db<>fiddle with the above. It also includes additional queries showing
The result from the CTE
The values used in the running total
Note that while it possible to do this with recursive CTEs, they tend to have performance problems (they are loops, fundamentally). Soit is better (performance-wise) to avoid recursive CTEs if possible.

T-SQL to sum total value instead of rejoining table multiple times

I've looked for an example question like this, I ask for grace if it's been answered (I thought it would have been but have a hard time finding meaningful results with the terms I searched.)
I work at a manufacturing plant where at ever manufacturing operation a part is issued a new serial number. The database table I have to work with has the serial number recorded in the Container field and the previous serial number the part had recorded in the From_Container field.
I'm trying to SUM the Extended_Cost column on parts we've had to re-do operations on.
Here's a sample of data from tbl_Container:
Container From_Container Extended_Cost Part_Key Operation
10 9 10 PN_100 60
9 8 10 PN_100 50
8 7 10 PN_100 40
7 6 10 PN_100 30
6 5 10 PN_100 20
5 4 10 PN_100 50
4 3 10 PN_100 40
3 2 10 PN_100 30
2 1 10 PN_100 20
1 100 10 PN_100 10
In this example the SUM I would expect returned is 40, because operations 20, 30, 40 and 50 were all re-done and cost $10 each.
So far I've been able to do this by rejoining the table to itself 10 times using aliases in the following fashion:
LEFT OUTER JOIN tbl_Container AS FCP_1
ON tbl_Container.From_Container = FCP_1.Container
AND FCP_1.Operation <= tbl_Container.Operation
AND tbl_Container.Part_Key = FCP_1.Part_Key
And then using SUM to add the Extended_Cost fields together. However, I'm violating the DRY principle and there has got to be a better way.
Thank you in advance for your help,
Me
You can try this query.
;WITH CTE AS
(
SELECT TOP 1 *, I = 0 FROM tbl_Container C ORDER BY Container
UNION ALL
SELECT T.*, I = I + 1 FROM CTE
INNER JOIN tbl_Container T
ON CTE.Container = T.From_Container
AND CTE.Part_Key = T.Part_Key
)
SELECT Part_Key, SUM(T1.Extended_Cost) Sum_Extended_Cost FROM CTE T1
WHERE
EXISTS( SELECT * FROM
CTE T2 WHERE
T1.Operation = T2.Operation
AND T1.I > T2.I )
GROUP BY Part_Key
Result:
Part_Key Sum_Extended_Cost
---------- -----------------
PN_100 40

Resources