SQL Server query : get the sum conditionally - c#

Given data
I need to come up to this by including SalesNew column:
SalesNew column will compute for the sum of each items sales based on their group number conditionally.
Example based on the table above. when the group number of item is 1, IT WILL JUST COPY OR RETAIN ITS SALES. When it is not 1, SalesNew column should get the sum of all items per group, like in the given example, salesNew displays 20 for item 3 and item 4 because it adds their sales that both having 10. So item 3 and 4 salesNew value is 20.
I know the sum function but this doesn't display the desired output. I hope anyone could help me out on this.
Thanks in advance

You could use SUM(Sales) OVER(PARTITION BY [Group]), with a combination of CASE:
SELECT *,
salesNew =
CASE
WHEN [Group] = 1 THEN Sales
ELSE SUM(Sales) OVER(PARTITION BY [Group])
END
FROM Data
SQL Fiddle
You could also use CROSS APPLY:
SELECT
d.*,
salesNew =
CASE
WHEN [Group] = 1 THEN Sales
ELSE x.salesNew
END
FROM Data d
CROSS APPLY(
SELECT salesNew = SUM(Sales)
FROM Data
WHERE [Group] = d.[Group]
)x
SQL Fiddle

Related

Calculate a Running Total plus minus with merge column

I have a table with five column description, opening balance, sale, sale return, recipt.
I want to merge opening balance, sale as "Debit" and salereturn, recipt as "Credit".
How to calculate running total as column name as "balance" debit amount plus and credit amount MINUS in balance column?
My attempt is
SELECT Description, (InvoiceAmount + OpeningBalance) as 'Dabit', (DrAmount + SaleReturn + BadDebtAmount) as 'credit', SUM (sale+ OpeningBalance-SaleReturn-recipt) over (ORDER BY id) AS RunningAgeTotal FROM tablename
You seem to be describing coalesce() and a window function:
select description,
coalesce(opening, sale) as debit,
coalesce(return, receipt) as credit,
sum(coalesce(opening, sale, 0) - coalesce(return, receipt, 0)) over (order by order by (case description when 'opening balance' then 1 when 'sale' then 2 when 'sale return' then 3 else 4 end))
from t
order by (case description when 'opening balance' then 1 when 'sale' then 2 when 'sale return' then 3 else 4 end);
At the expense of creating a temporary list, a Linq version would be as follows :
Assuming your original source is from a Sql database, then you first need to bring the data into memory, eg
var records = OrderDetails
.OrderBy(a=>a.Date)
.Select(a => new
{
a.Description,
Debit = a.OpeningBalance + a.Sale,
Credit = a.Return + a.SaleReturn
}
)
.ToList();
Note the query needs to be sorted to ensure the date is returned in the correct order. You haven't mentioned any other fields, so I have just assumed there is a field called date that can be used.
Once you have the data in memory, you can then add the Balance column, ie
decimal balance = 0;
var list = records.Select(a => new
{
a.Description,
a.Debit,
a.Credit,
Balance = balance += (a.Debit - a.Credit),
}).ToList();
Because you are introducing a local variable and initialising it outside the Linq statement, it is important that the query is not enumerated twice unless balance has been reset to zero. You can avoid this by using .ToList(); or .ToArray();

Leaderboard, rank query, how to return the rows above/below a users rank

Given this query, if I want to pull the rank of a specific individual where I know there $name and $score and return the rows above/below that rank (say +/- 4), how would I go about doing that?
$query = "SELECT #curRank := #curRank + 1 AS Rank,
uniqueID,
name,
score
FROM scores, (SELECT #curRank := 0) r
ORDER by score DESC";
I'm coding in php, using MySQL and C# in Unity. My game is making a call to the server and running the php code. Goal is to echo the information and parse the information back in the game.
Any help would be much appreciated :)
Based off of your :=, I'm assuming you are using PostgreSQL, correct? I'm more familiar with the T-SQL syntax; but regardless, both PostgreSQL and T-SQL have windowing functions. You could implement something similar to the following (I left out variables for you to fill-in):
$query = "WITH scoreOrder
AS
(
SELECT uniqueID,
name,
score,
ROW_NUMBER() OVER (ORDER BY score DESC, uniqueID DESC) AS RowNum
FROM scores
ORDER BY uniqueID DESC
)
SELECT ns.*
FROM scoreOrder ms --Your matching score
INNER JOIN scoreOrder ns --Your nearby scores
ON ms.name = /* your name variable */
AND ms.score = /* your score variable */
AND ns.RowNum BETWEEN ms.RowNum - /* your offset */ and ms.RowNum + /* your offset */";
Explanation: First, we're creating a common table expression called scoreOrder, and projecting a RowNum column for your scores. In short, ROW_NUMBER() OVER (ORDER BY score DESC, uniqueID DESC) is just saying, "I am returning the row number of this record ordered by score and uniqueID, both descending and in that order." Then, you join that CTE with itself... ms will be your score that you match with, and you join that with ns where the ns.RowNum will be between your ms.RowNum, plus or minus your offset.
There are a ton of other windowing functions. Here are some others that could be more or less appropriate for your scenario:
ROW_NUMBER() - the rownumber of the record
RANK() - the rank of the record, duplicating in ties and includes
gaps (i.e., if 2nd place ties, you would have 1st, 2nd, 2nd,
4th)
DENSE_RANK() - same as rank, except that it fills in the gaps
(i.e., if 2nd place ties, you would have 1st, 2nd, 2nd, 3rd)
For more info, check the PostgreSQL documentation on windowing functions and their tutorial
Update:
Unfornately, MySQL does not support windowing functions or common table expressions. In your scenario, you will have to put the results of your previous query into a temp table, then doing a similar join as demonstrated above. So for example...
CREATE TEMPORARY TABLE IF NOT EXISTS allRankings AS
(
SELECT #curRank := #curRank + 1 AS Rank,
uniqueID,
name,
score
FROM scores, (SELECT #curRank := 0) r
ORDER by score DESC, uniqueID
);
SELECT r.*
FROM allRankings r
INNER JOIN allRankings myRank
ON r.Rank BETWEEN myRank.Rank - <your offset> AND myRank.Rank + <your offset>
AND myRank.name = <your name>
AND myRank.score = <your score>
ORDER by r.Rank;
Here is a SQLFiddle link for an example. (I'm not using a temp table on SQLFiddle because you have to build tables in the Build Schema window).

Missing number if no missing number, add max number + 1

I want a sql query:
I have list of number and want to find out the FIRST missing number if there is no missing number in the list then give me the next available number
for example I have a column data 1,2,4, that means I need three which is a missing number and If i have 1,2,3,4 then i need number 5. Please help thanks
You could use this query:
SELECT MIN(t1.Number) + 1 AS MissingNumber
FROM dbo.TableName t1
LEFT OUTER JOIN dbo.TableName t2
ON (t1.Number + 1 = t2.Number)
WHERE t2.Number IS NULL
However, this is a race condition, the first wins. Normally you should not fill gaps. If it's a key column you could use an IDENTITY column with auto increment.
-- Note the +1, so to include the next number if the sequence is "complete",
-- And the isnull(,0) to handle the "empty table" case
declare #m as int = (select isnull(max(id), 0) + 1 from yourtable)
-- Sequence 1...#m of numbers
;with t as (
select 1 x
union all
select x + 1
from t
where x <= #m)
-- Find the minimum missing numebr
select min(x) from t where not exists (select 1 from yourtable where id = x)
Where yourtable is the table you want to find the missing numbers from and id is the column of which you want to find the missing numbers.

Column is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause

This may be a very silly mistake but I just can't fix it. I have 2 tables, Questions and Questions_Rating.
Questions:
question_id question user_id
------------------------------------------
1 'How to blablabla' 1
2 'bla bla bla' 1
Questions_Rating
In this table, users will rate questions either by +1 or -1
question_rating_id question_id user_id rate
------------------------------------------------------
1 1 2 (+1)
2 1 3 (+1)
3 1 4 ( 1)
Now I would simply like to fetch the question from the questions table, and the SUM of the rate in the questions_rating table for this question, which has an ID = 1.
String QUERY = "SELECT q.question, SUM(r.rate) FROM questions q, questions_rating r WHERE r.question_id = q.question_id AND q.question_id = 1";
And this is what I'm getting.
Column 'questions.question' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
I know that the SUM of the rate will return 1 row, and the question is supposedly 1 row, I can't figure out what's wrong with this query.
I am using SQL Server 2008.
You will have to Group the values as per the question so you need a
GROUP BY q.question
at the end of your query
Good Explanation here
You need the group by q.question in your SQL statement.
Your Sum is suppose to return only a single row against the table, since you are selecting a column along with the Sum you need to specify a group on the selected column. In your case it should be q.question, and sum will be applied to each group of questions.
SELECT q.question,SUM(r.rate) AS RateSum
FROM questions q,questions_rating r
WHERE r.question_id = q.question_id AND q.question_id=1
GROUP BY q.question
or (using ANSI 92 style joins)
SELECT q.question,SUM(r.rate) AS RateSum
FROM questions q INNER JOIN questions_rating r ON r.question_id = q.question_id
WHERE q.question_id=1
GROUP BY q.question
or (using subqueries)
SELECT q.question, (SELECT SUM(r.rate) FROM questions_rating r WHERE r.question_id = q.question_id) AS RateSum
FROM questions q
WHERE q.question_id=1
You are missing group by clause in your select statement.
As you have used sum() function which is an aggregate function
So you need to write group by for all the select columns.
String QUERY = "SELECT
q.question,
SUM(r.rate)
FROM
questions q,
questions_rating r
where
r.question_id = q.question_id AND
q.question_id=1
group by
q.question";

order by desc didnt not arrange my data

once there are new data insert to my DB my rcount will increase by 1, what am i trying to do is to display latest inserted record to users, but i cant get my expected result
rCount in my datebase
1
2
3
4
5
output
5
4
3
1
2
expected output
5
4
3
2
1
"SELECT *, ROW_NUMBER() OVER (ORDER BY rCount DESC) AS 'RowNumber'
FROM [MovieListTable]"
Instead of using the row number you should introduce a numeric primary key (i.e. Id) and make it an Identity column. Now you can just select the row that has the maximum Id value:
select top 1 * from MovieListTable order by Id desc
Or to get all rows:
select * from MovieListTable order by Id desc

Categories

Resources