I'm using an MS Access .mdb database in my C# application. The database contains email messages (one row - one message).
I need to get a specified amount of messages which are older than a specified datetime. Let's say, 30 messages before 2012-02-01 12:00:00. I've tried different queries but all of them give me errors. Have tried the TOP, LIMIT and other statements also:
"SELECT * FROM ( SELECT * FROM Mails WHERE (timeReceived < ?) ) LIMIT 0,30";
"SELECT * FROM Mails WHERE (timeReceived = ?) ORDER BY timeReceived DESC LIMIT ?";
etc.
Any hints appriciated.
You say you've tried TOP clause, but it should work
SELECT TOP 30 * FROM Mails WHERE timeReceived < '2012-02-01 12:00:00' ORDER BY timeReceived DESC
You must take this into account.
The top directive doesn't return the top n items, as one is easily led
to believe. Instead it returns at least n distinct items determined by
the ordering of the result.
Edit to clarify:
SELECT TOP 25
FirstName, LastName
FROM Students
WHERE GraduationYear = 2003
ORDER BY GradePointAverage DESC;
http://office.microsoft.com/en-us/access-help/results.aspx?qu=top&ex=1&origin=HA010256402
The TOP predicate does not choose between equal values. In the
preceding example, if the twenty-fifth and twenty-sixth highest grade
point averages are the same, the query will return 26 records.
So, no, rows with the same timestamp are not skipped. But if the 30th and 31th records(according to the order clause) have the same timestamp, both will be returned and you get 31 records.
If you want to force 30 records to be returned, you need to include the primary key into the Order By to differentiate between tied values:
SELECT TOP 30 *
FROM Mails
WHERE timeReceived < '2012-02-01 12:00:00'
ORDER BY timeReceived DESC, MailID ASC
You can try this SQL out:
SELECT top 30 * FROM Mails WHERE timeReceived < #2012-02-01#
This should work (unverified):
SELECT top 30 *
FROM Mails
WHERE timeReceived < '2012-02-01 12:00:00'
ORDER BY timeReceived desc
Related
The database stores the currency exchange rate on a given day. Each day, one currency exchange value is collected and stored in the database as:
ID (int, AI)
VALUE
DATE
1
2.5
20.01.2021
2
2.7
21.01.2021
3
2.6
22.01.2021
If I would like to calculate the average exchange rate from the last 10 days, should I first sort the data by date and only retrieve the last 10 records when downloading the data, or is it enough to download the last 10 records from the database without sorting?
You can simply do in SQL Server database
SELECT TOP 10 AVG(VALUE) AS AverageRate
FROM YourTable
ORDER BY Id DESC
Concept should be same in other relational databases.
Tables (and table expressions such as views and CTEs) in SQL represent unordered sets. To get data in a particular order, you must specify an ORDER BY clause.
In fairly generic SQL you can do
SELECT AVG(VALUE) AS AverageRate
FROM (
SELECT VALUE
FROM YourTable AS t
ORDER BY Id DESC
OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY
) AS t
In some RDBMSs, instead of OFFSET FETCH, you use either LIMIT or TOP to achieve the same effect. You still need ORDER BY.
You can do it in both ways.
If you're using SQL with Dapper or ADO.NET, then you can write a query.
It should be sorted if you need the last 10 values
SELECT TOP 10 AVG(your value) AS average
FROM YourCurrencyExchangeTable
ORDER BY DATE DESC
If you're using EntityFrameWorkCore, you can write
var avg = db.yourDbContext
.Where(c => c.Date >= tenDaysAgoDate)
.Average(c => c.yourValue)
I hope my answer helps :)
Basically you have to sort first ( on date) and then get the last 10 values, so you're on the right track.
I am creating a patient booking system using ASP.NET.
I want to limit the number of bookings to 25 per day.
Using a suggestion, I have obtained the following SQL Trigger Code:
CREATE TRIGGER trg_CheckAppointmentCount ON dbo.schedule_master AFTER
INSERT,UPDATE
AS BEGIN
IF EXISTS (SELECT 1
FROM dbo.schedule_master YT
WHERE YT. Schedule_Date IN (SELECT i Schedule_Date FROM inserted)
GROUP BY YT. Schedule_Date
HAVING COUNT(YT.KeyColumn) > 25)
THROW 50012, N'Cannot have more than 25 appointments on a single day.', 16;
END;
GO
But I don't have a KeyColumn. Please suggest any changes.
This would better handled in the SQL Server side of things, in my opinion. you won't be able to do this with a CONSTRAINT but you could use a trigger. This is Pseudo-SQL, but perhaps something like this:
CREATE TRIGGER trg_CheckAppointmentCount ON dbo.YourTable
AFTER INSERT,UPDATE
AS BEGIN
IF EXISTS (SELECT 1
FROM dbo.YourTable YT
WHERE YT.DateColumn IN (SELECT i.DateColumn FROM inserted i)
GROUP BY YT.DateColumn
HAVING COUNT(YT.KeyColumn) > 25)
THROW 50012, N'Cannot have more than 25 appointments on a single day.', 16;
END;
GO
I wonder why would you limit the number of booking; However; this can be acheived just by a simple counter in your backend system. Perhasps some configuration of max record so that you can change it in future rather just limit it to 25. So get the total records created while new booking is getting created; and if it's > than config limit ( in this case 25) , just display a message back to the user.
Hope this helps you to build the logic.
Greeting
I am new with SQL Server i have a table Transaction with the attribute Debit, Credit and other columns, i want to calculate balance but i cant use CTE Query
expect result should be like ....
Debit Credit Balance
10,000 0 10,000
0 3,0000 7,000
5,000 0 12,000
previously i did it in mysql using variables as below
SELECT A.Debit,A.Credit, #b := #b + A.Debit - A.Credit AS balance
FROM (SELECT #b := 0.0) AS dummy
CROSS JOIN FinTrans A
but I am new to MSSQL SERVER How do I do it in MSSQLSERVER
Thanks in Advance
In SQL Server 2012, you would use the ANSI standard cumulative sum functions:
select ft.*,
sum(debit - credit) over (order by ??) as balance
from FinTrans ft;
SQL tables represent unordered sets. The ?? is for the column that specifies the ordering for your cumulative sum.
In fact, this might typically look like:
select ft.*,
sum(debit - credit) over (partition by <account id column>
order by <ordering column
) as balance
from FinTrans ft;
That is, this is how you would do the calculation for different accounts at the same time.
I need to get an automatic method to link certain number consumptions with a payment.
I have for example in my first table.
Payments
ID Amount
1 $5,000
Then I have the following Table:
Consumptions
ID Amount CreatedDate
1 1000 2015-07-01 13:59
2 1000 2015-07-01 19:15
3 1000 2015-07-02 01:01
4 1500 2015-07-02 08:44
5 1000 2015-07-03 05:00
6 800 2015-07-03 19:57
7 200 2015-07-03 21:32
8 500 2015-07-03 23:48
I want to have a way that considering the $5000 payment amount, it automatically chooses the best combination of consumptions that make up the $5,000 sum.
If SQL is difficult, it can also be done on C#.
You will need a CTE that recursively joins with itself and checks all possible combinations.
with Anchor
(
Select Id, Amount, 0 as Level
From Consumptions
),
with RecursiveJoin
(
Select Id, Amount, Level From Anchor
Where Level = 0
UNION ALL
-- generate all possible permutations of amounts
Select c2.Id, c1.Amount + c2.Amount, Level + 1
From RecursiveJoin c1
Left Join RecursiveJoin c2 on c1.Id < c2.Id -- eliminate self joins and palindromes
)
Select *
From RecursiveJoin c
Join Payments p on c.Amount = p.Amount
I'm not completely confident that my recursion is correct. Hopefully that gets you started on the concept.
I'll leave it to you to add fields that concatenate lists of Id's of consumptions in each recursion.
It will give you multiple matches since multiple combinations of consumptions could match a payment. You could find the one with fewest combinations by keeping count in the recursion.
I have a table with emails (called Mails) and I want to mark particular messages as assigned to different teams of workers (eg. team01, team02 etc). The msg<->team relations are kept in another table (called MailAssignments). I'm trying to get messages which are marked as being for just one team (let's say team01) and the message ID should be less than a specified value so that the set of messages is narrowed down to, lets say, 10.
I've got the below query but it always shows ALL messages assigned to the team isntead of showing only the ones with msgId < specified.
What is wrong with my query?
string queryGetMails =
"SELECT TOP 10 * FROM Mails WHERE msgId IN (SELECT msgId FROM MailAssignments WHERE (forTeam='team01') AND (msgId < ?) )";
I've also tried this (and the result is the same) :/
"SELECT TOP 10 * FROM Mails WHERE (msgId<?) AND (msgId IN (SELECT msgId FROM MailAssignments WHERE forTeam='team01' ) )";
Why do you insist with subqueries and in clause when it seems that you have a clear join between the two tables? Have you tried this?
SELECT TOP 10 Mails.*
FROM Mails left join
MailAssignments On Mails.msgID = MailAssignments.msgID
WHERE Mails.msgId < ? AND MailAssignments.forTeam = 'team01'