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();
Related
I have a method in my controller which returns a PagedList to my category-page View that contains Products (based current Page-Number and Page-Size which user has selected) from SQL Server stored-procedure like blow :
var products = _dbContext.EntityFromSql<Product>("ProductLoad",
pCategoryIds,
pManufacturerId,
pOrderBy,
pageIndex,
pageSize).ToList(); // returning products based selected Ordering by.
var totalRecords = pTotalRecords.Value != DBNull.Value ? Convert.ToInt32(pTotalRecords.Value) : 0;
var allPrd= new PagedList<Product>(products, pageIndex, pageSize, totalRecords);
An Example of sending parameters to db stored-procedure is :
("ProductLoad",
[1,10,13],
[653],
"Lowest Price",
2,
64) // so it returns second 64 products with those category-ids and Brand-ids sorting by lowest to highest price
It's working fine , but what i am trying to do is always sending products with 0 quantity to the end of list.
For example :
if i had 10k products which 2k of them have 0 quantity , i need to show this 8k products first and then 2k unavailable products in the end of list)
what i have tried so far is always loading All products without page-size and page-index first then send zero qty products to the end of the list by this and finally Pagedlist with fixing page size :
("ProductLoad",
[1,10,13],
[653],
"Lowest Price",
0,
10000) // fixed page size means loading all products
var zeroQty= from p in products
where p.StockQuantity==0
select p;
var zeroQtyList= zeroQty.ToList();
products = products.Except(zeroQtyList).ToList();
products.AddRange(zeroQtyList);
var totalRecords = pTotalRecords.Value != DBNull.Value ? Convert.ToInt32(pTotalRecords.Value) : 0;
var allPrd= new PagedList<Product>(products, pageIndex, 64, totalRecords);
It cause all zero qty Products goes to the end of list.
But it always loads all products that is not a good idea and for sure not an optimized way , sometime users get page loading time-out,
(because category-page show 64 products in every page-index-number) every time user opens a page in the website, all products would loads and it cause delay in loading page.
Is there anyway to solve this problem (have a PagedList which
contains all more than zero qty products first and 0 qty products
second) without changing stored-procedure? (fixing loading page
delays)
P.S : The reason i avoid changing stored-procedure is it has already too much join,temp-table Union and Order by.
Any help would be appreciated.
You will need to the use the ROW_NUMBER function in your stored procedure.
This is an example of how I have done this before. Hopefully you will be able to adapt it to your SP.
--temp table to hold the message IDs we are looking for
CREATE TABLE #ids (
MessageId UNIQUEIDENTIFIER
,RowNum INT PRIMARY KEY
);
--insert all message IDs that match the search criteria, with row number
INSERT INTO #ids
SELECT m.[MessageId]
,ROW_NUMBER() OVER (ORDER BY CreatedUTC DESC)
FROM [dbo].[Message] m WITH (NOLOCK)
WHERE ....
DECLARE #total INT;
SELECT #total = COUNT(1) FROM #ids;
--determine which records we want to select
--note: #skip and #take are parameters of the procedure
IF #take IS NULL
SET #take = #total;
DECLARE #startRow INT, #endRow INT;
SET #startRow = #skip + 1;
SET #endRow = #skip + #take;
-- select the messages within the requested range
SELECT m.* FROM [dbo].[Message] WITH (NOLOCK)
INNER JOIN #ids i ON m.MessageId = i.MessageId
WHERE i.RowNum BETWEEN #startRow AND #endRow;
OrderByDescending could be useful to fix it. Like below:
List<Product> SortedList = products.OrderByDescending(o => o.StockQuantity).ToList();
first time I ask a question here, I'm coding a reservations application on C# using Visual Studio 2015, but I have a problem trying to show free rooms on a data grid view, here is the query i'm using:
SELECT clientID, cost, arrival, roomNumber, resvNum, departure, size
FROM roomswithresvView
WHERE (roomNumber NOT IN
(SELECT roomNumber
FROM roomswithresvView AS roomswithresvView_1
WHERE (arrival BETWEEN #date1 AND #date2)
OR (departure BETWEEN #date1 AND #date2)))
The problem is that if a room has more than one reservation, the query will show it multiple times, I have tried using DISTINCT but I can only make work with one column and I haven't been able to make GROUP BY work.
Thanks for your attention.
Query Sample
For example, if I test the query with 2016-07-06 as date1 and 2016-07-07 as date2, it will repeat room 1005 because it has two reservations on the database.
Where were you putting the DISTINCT?
You need a table for rooms, and a table for reservations. Then you need a subquery to find reservations that clash with your requested dates. This is where you use DISTINCT. Then you need an outer query to find all rooms not returned in the subquery. Don't forget the case where you have an existing reservation that starts before and ends after your requested dates! Putting that all together, you get this...
insert into room(costPerNight, roomNumber, size)
values
(55, 1, 13),
(65, 2, 15),
(85, 3, 20)
;
create table reservation(
id int identity (1,1) not null,
roomId int not null,
dateIn date not null,
dateOut date not null
)
insert into reservation (roomId, dateIn, dateOut)
values
(1,'2016-07-01','2016-07-03'),
(1,'2016-07-05','2016-07-08'),
(2,'2016-07-01','2016-07-08')
*/
declare #requestedDateIn date = '2016-07-03'
declare #requestedDateOut date = '2016-07-05';
select * from room where id not in(
--find clashing reservations
select distinct roomId from reservation where
(dateOut > #requestedDateIn and dateOut < #requestedDateOut)
or (dateIn > #requestedDateIn and dateIn < #requestedDateOut)
or (dateIn < #requestedDateIn and dateOut > #requestedDateOut)
)
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
I have 3 columns in my database. (1) Buy/Sell (2) ID (3) Date and time. For example:
buySel ID Date
1 234 12/12/2014
1 234 12/12/2014
2 234 12/12/2014
In buySell the number (1) is represented as buy and (2) is sell. Within the same day if the ID e.g. '234' is bought and sold this should return a error message.
This is what I have done in C#
string connectionString= "connection string goes here";
string Query = "SELECT COUNT(*) AS sum from databaseTable WHERE created_time >= DATEADD(hour, 9, CONVERT(DATETIME, CONVERT(DATE, GETDATE())))";
........
SqlDataReader data;
try
{
con.Open();
myReader = cmdg.ExecuteReader();
while (data.Read())
{
if (myReader[0].ToString() != "0")
{
MessageBox.Show("Error " + myReader[0].ToString());
}
}
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
I managed to compare it with today's date however how will I compare it to the buySell column and the ID column?
I'm not sure exactly what you want to return. The following will identify all the errors in your data, based on having a buy and sell in the same day:
select id, date
from databaseTable t
group by id, date
having sum(case when buysel = 1 then 1 else 0 end) > 0 and
sum(case when buysel = 2 then 1 else 0 end) > 0;
I'll like #GordonLinoff's answer, but haven't compared it performance wise to what you would get from a using EXISTS with correlated subqueries.
create table databaseTable (buySel TINYINT, ID INT, [Date] DATE)
insert into databaseTable values
(1,234,'12/12/2014'),
(1,234,'12/12/2014'),
(2,234,'12/12/2014')
select id
,[Date]
from databaseTable a
where exists(select 1 from databaseTable b where b.id=a.id
and b.[Date] = a.[Date]
and buysel = 1)
and exists(select 1 from databaseTable b where b.id=a.id
and b.[Date] = a.[Date]
and buysel = 2)
group by id
,[Date]
In this query the group by serves only as a more efficient DISTINCT.
EDIT:
Since the above statement has been questioned I figure I should examine it more closely. There a lot of discussion here and on the web at large. I think the sum of the guidance would be that GROUP BY is often more efficient then DISTINCT, but not always and DISTINCT is more intuitive a syntax.
Huge performance difference when using group by vs distinct
When the performance of Distinct and Group By are different?
http://msmvps.com/blogs/robfarley/archive/2007/03/24/group-by-v-distinct-group-by-wins.aspx
I am writing a piece of code which is going to order the list of photos based on their rating. Each photo is stored in DB, and each has such information as number of positive and negative votes. I want to order them by the formula in which I count the percentage of positive votes, and the first photo is the one with the highest percentage.
For that I used the standard IComparer interface, and wrote my own Comparer function, which compares two photos. The problem is that I do that I have to first download the list of all photos from the db. It seems like a lot of unnecessary effort which I would like to avoid. So I am wondering if it is possible to create my own SQL function which will do the comparing on the DB side, and returns to me just the photos I want? It is more efficient than comparing all the photos on the server side?
The code for my own comparer:
public class PictureComparer : IComparer<Picture>
{
public int Compare(Picture p1, Picture p2)
{
double firstPictureScore = (((double)p1.PositiveVotes/(double)(p1.PositiveVotes+p1.NegativeVotes))*100);
double secondPictureScore = (((double)p2.PositiveVotes / (double)(p2.PositiveVotes + p2.NegativeVotes)) * 100);
if (firstPictureScore < secondPictureScore) return 1;
if (firstPictureScore > secondPictureScore) return -1;
return 0;
}
}
And the code which uses the comaprer:
var pictures = db.Pictures.Include(q => q.Tags).Include(q => q.User).ToList();
pictures = pictures.OrderBy(q => q, new PictureComparer()).Skip(0 * 10).Take(10).ToList();
Remove the first call to ToList and use a lambda expression instead of defining a comparer:
var result = db.Pictures
.Include(q => q.Tags)
.Include(q => q.User)
.OrderByDescending(q =>
q.PositiveVotes + q.NegativeVotes == 0
? -1
: q.PositiveVotes / (double)(q.PositiveVotes + q.NegativeVotes))
.Skip(n * 10)
.Take(10)
.ToList();
The calculations in your comparer code are independent (i.e. the comparison just depends on ordering a value that can be calculated without reference to the item you are comparing to). Therefore you should calculate your positive percentage number first and just use the calculated value in your comparer.
This should certainly be done in the database if possible (i.e. if you have access to make changes to the database). Databases are suited to this kind of calculation and you could probably do it on the fly without having to cache the calculated values, by which I mean have a view that works out the percentage for you rather than precalculating and storing the value everytime there is a positive or negative vote. This will obviate the need to download all the photos to compare, as you can just order by the positive percentage. Below is some sample sql that will do the job (note it is only a sample...you might want to store the vote as a bit or something more efficient). The votes table contains a list of all votes for a particular picture and who voted for it.
declare #votes table(
pictureId int,
voterId int,
vote int)
insert into #votes select 1,1,1
insert into #votes select 1,2,-1
insert into #votes select 1,3,1
insert into #votes select 1,4,1
insert into #votes select 2,1,-1
insert into #votes select 2,2,-1
insert into #votes select 2,3,1
insert into #votes select 2,4,1
declare #votesView table(
pictureId int,
positiveVotes int,
NegativeVotes int)
insert into #votesView
select pictureId, sum(case when vote > 0 then 1 else 0 end) as PositiveVotes,
SUM(case when vote < 0 then 1 else 0 end) as NegativeVotes from #votes group by pictureId
select pictureId, convert(decimal(6,2),positiveVotes) / convert(decimal(6,2), (positiveVotes + negativeVotes)) as rating from #votesView