I'm having some issues grouping by an Alias column in SQL. This column contains both positive and negative numbers, and as a result, I want my "ARI_APLNO" column to be the sum of both the positive and negative numbers.
This is the code I currently have:
SELECT ARI_APLNO,
CASE
WHEN ARI_TYPE = 1 OR ARI_TYPE = 3 THEN ARI_AMOUNT + ARI_SLSTAX
WHEN ARI_TYPE = 2 AND ARI_AMOUNT < 0 THEN ARI_AMOUNT * - 1
WHEN ARI_TYPE = 5 THEN (ARI_AMOUNT + ARI_SLSTAX) * - 1
ELSE - ARI_AMOUNT END AS TotalValue
FROM dbo.ARITEMA
GROUP BY TotalValue, ARI_APLNO
Wondering if I could please have some assistance?
Thank you in advance.
;WITH CTE AS (
SELECT ARI_APLNO,
CASE
WHEN ARI_TYPE = 1 OR ARI_TYPE = 3 THEN ARI_AMOUNT + ARI_SLSTAX
WHEN ARI_TYPE = 2 AND ARI_AMOUNT < 0 THEN ARI_AMOUNT * - 1
WHEN ARI_TYPE = 5 THEN (ARI_AMOUNT + ARI_SLSTAX) * - 1
ELSE - ARI_AMOUNT END AS TotalValue
FROM dbo.ARITEMA
)
SELECT ARI_APLNO,SUM(TotalValue) FROM CTE
GROUP BY ARI_APLNO
Try framing a CTE with all the conversions and then do SUM which will be easier and clean to handle new changes in future.
Related
I have a query with 2 different return nodes. My question is why when I return m2 node, result will change and when remove m2 node from return statement, result will change too. result dcount change by removing or adding m2. my question is why?!!
first query with m2 in return statement:
MATCH (a1:Example)<-[r1:REL_EXAMPLE]-(a2:Example),
(a1)-[:REL_2_EXAMPLE]->(m1:Mexample),
(a2)-[:REL_2_EXAMPLE]->(m2:Mexample)
WHERE a1.key = 123456
AND a2.key <> a1.key
AND (r1.delta < 300 AND r1.delta > 20)
AND ((a1.love <> 0 OR a2.love <> 0) OR (abs(a1.love - a2.love) < 0.1))
WITH a1,a2,m1,m2,r1, CASE
WHEN exists((m1)<-[:REL_2_EXAMPLE]-(a2)) OR exists((m2)<-[:REL_2_EXAMPLE]-(a1)) THEN 0.20
ELSE 1
END AS factor
RETURN count(r1) * factor as dcount,a2.title as anode, a2.key as id, m2.full_name ORDER BY dcount DESC LIMIT 30;
second query without m2:
MATCH (a1:Example)<-[r1:REL_EXAMPLE]-(a2:Example),
(a1)-[:REL_2_EXAMPLE]->(m1:Mexample),
(a2)-[:REL_2_EXAMPLE]->(m2:Mexample)
WHERE a1.key = 123456
AND a2.key <> a1.key
AND (r1.delta < 300 AND r1.delta > 20)
AND ((a1.love <> 0 OR a2.love <> 0) OR (abs(a1.love - a2.love) < 0.1))
WITH a1,a2,m1,m2,r1, CASE
WHEN exists((m1)<-[:REL_2_EXAMPLE]-(a2)) OR exists((m2)<-[:REL_2_EXAMPLE]-(a1)) THEN 0.20
ELSE 1
END AS factor
RETURN count(r1) * factor as dcount,a2.title as anode, a2.key as id ORDER BY dcount DESC LIMIT 30;
This happens because you are performing an aggregation operation in the return statement. In the first query with m2 in the return statement.
RETURN count(r1) * factor as dcount,a2.title as anode, a2.key as id, m2.full_name ORDER BY dcount DESC LIMIT 30;
dcount is calculated for each distinct combination of a2.title, a2.key and m2.full_name.
In the second query, with the return statement
RETURN count(r1) * factor as dcount,a2.title as anode, a2.key as id ORDER BY dcount DESC LIMIT 30;
dcount is calculated, for each distinct combination of a2.title and a2.key, since the aggregation criteria for each query is different, hence the results are different.
Please read again till end (description updated)
I want something like this.
ex :
if (7200 / 42) is float then
floor(7200/42) + [7200 - {(floor(7200/42)) * 42}] / 10 ^ length of [7200 - {(floor(7200/42)) * 42}]
STEP : 1 => 171 + ((7200 - (171*42))/10 ^ len(7200-7182))
STEP : 2 => 171 + ((7200 - 7182)/10 ^ len(18))
STEP : 3 => 171 + (18/10 ^ 2)
STEP : 4 => 171 + (18/100)
STEP : 5 => 171 + 0.18
STEP : 6 => 171.18
I have written the code in SQL which actually works perfectly but the addition of 171 + 0.18 only gives 171
IF I can get "171/18" instead of "171.18" as string then it'd also be great. (/ is just used as separator and not a divison sign)
Following is the code I written
Here,
(FAP.FQTY + FAP.QTY) = 7200,
PRD.CRT = 42
(values only for example)
select
case when PRD.CRT <> 0 then
case when (FAP.FQTY + FAP.QTY)/PRD.CRT <> FLOOR((FAP.FQTY + FAP.QTY)/PRD.CRT) then --DETERMINE WHETHER VALUE IS FLOAT OR NOT
(floor((FAP.FQTY + FAP.QTY)/PRD.CRT)) +
((FAP.FQTY + FAP.QTY) - floor((FAP.FQTY + FAP.QTY)/PRD.CRT) * PRD.CRT) /
POWER(10, len(floor((FAP.FQTY + FAP.QTY) - floor((FAP.FQTY + FAP.QTY)/PRD.CRT) * PRD.CRT)))
else
(FAP.FQTY + FAP.QTY)/PRD.CRT -- INTEGER
end
else
0
end
from FAP inner join PRD on FAP.Comp_Year = PRD.Comp_Year and
FAP.Comp_No = PRD.Comp_No and FAP.Prd_Code = PRD.Prd_Code
I got all the values correct till 171 + 0.1800 correct but after that I am only receiving 171 in the addition. I want exactly 171.18.
REASON FOR THIS CONFUSING CALCULATION
Its all about accounting
Suppose, a box(or a cartoon) has 42 nos. of items.
A person sends 7200 items. how many boxes he has to send?
So that will be (7200/42) = 171.4257.
But boxes cannot be cut (its whole number i.e 171).
so 171 * 42 ie 7182 items.
Remaining items = 7200 - 7182 = 18.
So answer is 171 boxes and 18 items.
In short 171.18 or "171/18"
Please help me with this..
Thank you in advance.
Recognise that you're not producing an actual numeric result, I'd describe it as unhealthy to try to keep it using such a datatype1.
This produces the strings you're seeking, if I've understood your requirement:
;With StartingPoint as (
select 7200 as Dividend, 42 as Divisor
)
select
CONVERT(varchar(10),Quotient) +
CASE WHEN Remainder > 0 THEN '.' + CONVERT(varchar(10),Remainder)
ELSE '' END as FinalString
from
StartingPoint
cross apply
(select Dividend/Divisor as Quotient, Dividend % Divisor as Remainder) t
(Not tested for negative values. Some adjustments may be required. Technically % computes the modulus rather than the remainder, etc)
1Because someone might try and add two of these values together and I doubt that produces a correct result, not even necessarily if using the same Divisor to compute both.
Just another idea about how to calculate it.
Simple calculate the whole boxes.
And concatinate a dot with the remaining items (using a modulus).
Wrapped it all up in a CASE WHEN (or IIF) to avoid the divide by zero.
Example snippet:
declare #TestTable table (FQTY numeric(18,2), QTY numeric(18,2), CRT numeric(18,0));
insert into #TestTable (FQTY,QTY,CRT) values
(5000, 2200, 42),
(5000, 2200, 0),
( 100, 200, 10);
select *,
(CASE
WHEN CRT>0
THEN CONCAT(CAST(FLOOR((FQTY+QTY)/CRT) as INT),'/',CAST((FQTY+QTY)%CRT as INT))
ELSE '0'
END) AS Boxes
from #TestTable;
Result:
FQTY QTY CRT Boxes
------- ------- --- ------
5000.00 2200.00 42 171/18
5000.00 2200.00 0 0
100.00 200.00 10 30/0
The CONCAT returns a varchar, and so does the CASE WHEN.
But you could wrap that CASE WHEN in a CAST.
You're getting an automatic type conversion from int to decimal(10,0) which is probably not what you want.
https://learn.microsoft.com/en-us/sql/t-sql/data-types/int-bigint-smallint-and-tinyint-transact-sql?view=sql-server-2017
Check out the "Caution" box.
If you want a specific amount of precision, you'll need to explicitly cast() the values to the desired data type.
if i understand your logic correctly you want the remainder of 7200 divide by 42 and the remainder is to divide by 100
declare
#dividend int = 7200,
#divisor int = 42
select (#dividend / #divisor)
+ convert(decimal(10,4),
(#dividend % #divisor) * 1.0 / power(10, len(#dividend % #divisor)))
EDIT: change to handle the 10^len(remainder)
In SQL Server for calculating percentage I have a function like below:
CREATE FUNCTION [dbo].[fuGetPercentage] ( #part FLOAT, #total FLOAT )
RETURNS FLOAT
AS
BEGIN
DECLARE #Result FLOAT = 0, #Cent FLOAT = 100;
IF (isnull(#total, 0) != 0)
SET #Result = isnull(#part, 0) * #Cent / #total;
RETURN #Result
END
I wonder that is there any better alternative for that, with same checks and a better calculating percentage like below:
SELECT (CASE ISNULL(total, 0)
WHEN 0 THEN 0
ELSE ISNULL(part, 0) * 100 / total
END) as percentage
I want to use it directly after SELECT like above.
There is one issue with using functions such as ISNULL. The query will not use indexes in that case. If the beauty of the code isn't in the first place then you can do something like that:
SELECT
CASE WHEN total * part <> 0 /* will check that both total and part are not null and != 0*/
THEN part * 100 / total
ELSE 0
END AS percentage;
I use #DmitrijKultasev answer but now, I found that it has two problems:
Error on conversion because of the overflow of result of multiply.
Performance problem; because of that math multiply and its conversion.
So I change it to this:
SELECT
CASE
WHEN total <> 0 AND part <> 0 THEN -- This will return 0 for Null values
part * 100 / total
ELSE
0
END AS percentage;
I have a query that outputs some rows that I need to "filter".
The data I want to filter is like this:
rownum value
1 0
2 0
3 1
4 1
I need the first 2 rows, but only when they have "0" in the value-column.
The structure of the query is like this:
select count(x)
from
(
select row_number() over (partition by X order by y) as rownum, bla, bla
from [bla bla]
group by [bla bla]
) as temp
where
/* now this is where i want the magic to happen */
temp.rownum = 1 AND temp.value = 0
AND
temp.rownum = 2 AND temp.value = 0
So I want x only when row 1 and 2 have "0" in the value-column.
If either rownumber 1 or 2 have a "1" in the value-column, I dont want them.
I basically wrote the where-clause the way I wrote it here, but it's returning data sets that have "1" as value in either row 1 or 2.
How to fix this?
A value in a single row for a given column can never be both 1 and 2 at the same time.
So, first of all, either use OR (which is what I believe you intended):
WHERE (temp.rownum = 1 AND temp.value = 0)
OR (temp.rownum = 2 AND temp.value = 0)
Or simplify the query altogether:
WHERE temp.rownum <= 2 AND temp.value = 0
From here, you will get just the first two rows, and only if value = 0. If you only want rows when both rows are returned (i.e. both rows have value = 0), add
HAVING COUNT(1) = 2
to the query.
SELECT DEL_CD ,COUNT(DEL_CD) AS COUNT_NO
FROM [DATAStaging].[dbo].[DATASTORE]
GROUP BY DEL_CD
gives me this result
DEL_CD COUNT_NO
0 6442
1 12161
2 2342
But what do I have to do to the script to display the count number as a %
Total rows does = sum of count_no.
Thanks in advance
SELECT del_cd, COUNT(DEL_CD) * 100.0 / SUM(COUNT(DEL_CD)) OVER ()
FROM datastore
GROUP BY
del_cd