EF6, asp mvc core and SQL Server are used on the background.
I have to do many queries to the same table with different conditions, f.e.
SELECT COUNT(*) FROM Table1 WHERE a = true
SELECT COUNT(*) FROM Table1 WHERE b = true
SELECT COUNT(*) FROM Table1 WHERE a = true || b = true
SELECT a FROM Table1 WHERE b = true
So 4 queries to Table1 with different conditions. I think that as result I have to read the entire Table1 four times. In pseudo code it might be looking like this.
var res1 = new list();
foreach(var rec in Table1)
{
// read Table1 first time
if(rec.a == true)
{
res1.push(rec);
}
}
var res2 = new list();
foreach(var rec in Table1)
{
// read Table1 second time
if(rec.b == true)
{
res2.push(rec);
}
}
var res3 = new list();
foreach(var rec in Table1)
{
// read Table1 third time
if(rec.a == true || rec.b == true)
{
res3.push(rec);
}
}
var res4 = new list();
foreach(var rec in Table1)
{
// read Table1 fourth time
if(rec.b == true)
{
res4.push(rec);
}
}
I want to know how to read the Table1 only one time and get four different results, like this:
var res1 = new List();
var res2 = new List();
var res3 = new List();
var res4 = new list();
foreach(rec in Table1)
{
// read Table1 first time
if(a == true)
{
res1.push(rec);
}
if(b == true)
{
res2.push(rec);
}
if(a == true || b == true)
{
res3.push(rec);
}
if(b == true)
{
res4.push(rec);
}
}
Also the challenge, that those queries are dynamic sql, I mean that a = true, b = true, a = true || b = true are stored in database. And queries are running in this way:
string query = "SELECT Count(*) FROM Table1 WHERE" + condition;
var count = ExecuteSql(query);
The sample above is simplified, but in reality all the query is split and stored in database.
PS. Actually I want to speed up the page, which makes 30-40 requests to the server and each request is the query to the same table. I think if I can replace them with one request instead of 40 requests.
You may use conditional aggregation with just a single query:
SELECT
COUNT(CASE WHEN a = true THEN 1 END) AS cnt_a,
COUNT(CASE WHEN b = true THEN 1 END) AS cnt_b,
COUNT(CASE WHEN a = true OR b = true THEN 1 END) AS cnt_a_b
FROM Table1;
This would reduce the number of full table scans from 3 to just 1. Also, it would also potentially reduce the number of round trips to/from the database from 3 to 1.
Related
I'm currently working on a Spring Boot Webapp where I want to retreive tasks with JPA.
A Task can have multiple requirements and my customer creates requirement_answers which are connected to his wedding. I now want to select all tasks where all the requirement.answer_value are answered with 'true'.
My relevant Database Schema is:
My current query is this:
I now want to check that the task with the same uuid has all requirement_answer with true?
How can I achieve this?
Greetings
EDIT:
My Solution, filtered in Code instead of jpql as I could not get it working
#Query("""
select t, ra
from
Task t,
RequirementAnswer ra,
Requirement r,
Wedding w
where
ra.requirement = r and
w.id = :weddingId and
t member of r.tasks"
""")
fun findByWedding(weddingId: Long): List<Tuple>?
}
Here is the filtering:
fun getTasksByWedding(wedding: Wedding?): List<Task> {
val tasks: MutableMap<Task,String> = mutableMapOf()
wedding?.id?.let { taskRepository.findByWedding(it) } ?.map {
val task = it.get(0) as Task
val requirementAnswer = it.get(1) as RequirementAnswer
tasks[task]?.let { taskAnswer ->
if(taskAnswer != requirementAnswer.answerValue){
tasks.remove(task)
}
}?: let {
if(requirementAnswer.answerValue == "true"){
tasks[task] = requirementAnswer.answerValue
}
}
} ?: throw ResponseStatusException(HttpStatus.BAD_REQUEST, "Wedding doesn't exist")
return tasks.map { it.key }
}
With SQL you can do use subselects to compare the counts:
select t.*
from task t
join task_requirement tr on t.uuid = tr.task_id
join requirement r on tr.requirement_id = r.id
join requirement_answer ra1 on r.id = ra1.requirement_id
join wedding_requirement_answer wra1 on ra1.id = wra1.requirement_answer_id
where wra1.wedding_id = 1
and ( (select ra2.requirement_id
from requirement_answer ra2
join wedding_requirement_answer wra2 on ra2.id = wra2.requirement_answer_id
where wra2.wedding_id = wra1.wedding_id
and ra2.requirement_id = ra1.requirement_id))
=
(select ra3.requirement_id
from requirement_answer ra3
join wedding_requirement_answer wra3 on ra3.id = wra3.requirement_answer_id
where wra3.wedding_id = wra1.wedding_id
and ra3.requirement_id = ra1.requirement_id
and ra3.answer_value = 'true');
I'm doing a sample project where it counts the total issues per month that is to be displayed in a bar graph..
Here is my working SQL query
SELECT
SUM(CASE datepart(month,D_ISSUE) WHEN 1 THEN 1 ELSE 0 END) AS 'Jan',
SUM(CASE datepart(month,D_ISSUE) WHEN 2 THEN 1 ELSE 0 END) AS 'Feb',
so on...
FROM EMP_MEMOS
Can someone help me transpose this SQL Query into a LinQ code. i'm still trying to understand how it works
Here is my code so far, but i still can't get it to work.
public ActionResult MonthCount()
{
var Monthly = (from f in db.EMP_MEMOS
group f by new { month = f.D_ISSUE, year = f.D_ISSUE } into g
orderby g.Key.year
select new
{
dt = string.Format("{0}/{1}", g.Key.month, g.Key.year),
}).ToList();
return Json(new { result = Monthly }, JsonRequestBehavior.AllowGet);
}
I already got the answer, gonna share it here:
public ActionResult CountMonth()
{
var memo = from t in db.EMP_MEMOS
select new
{
t.D_ISSUE.Value.Month,
t.D_ISSUE.Value.Year
};
var res = from s in memo
group s by new { s.Year, s.Month } into g
select new
{
Period = g.Key,
MemoCount = g.Count(),
};
return Json(new { result = res }, JsonRequestBehavior.AllowGet);
}
Codes inside Weekly returns a value. But in Monthly it returns null.
I tried to run the query in my SQL Server Management Studio and it returns the correct result. But in my code, it returns null.
I tried to breakpoint and the item.JobId is = 2.
Here is my codes.
if (item.Frequency == "Weekly")
{
if (item.StartDate.DayOfWeek.ToString() == DateTime.Now.DayOfWeek.ToString())
{
var jobname = _context.Jobs.Where(x => x.Id == item.JobId).FirstOrDefault();
if (ModelState.IsValid)
{
jobs.Id = 0;
jobs.Job = jobname.Job;
jobs.ClientName = jobname.ClientName;
jobs.ClientId = jobname.ClientId;
jobs.JobRate = jobname.JobRate;
jobs.Status = "Active";
}
}
}
else if (item.Frequency == "Monthly")
{
if (item.StartDate.Day.ToString() == DateTime.Now.Day.ToString())
{
var jobname = _context.Jobs.Where(x => x.Id == item.JobId).FirstOrDefault();
var a = jobname.Job;
if (ModelState.IsValid)
{
jobs.Id = 0;
jobs.Job = jobname.Job;
jobs.ClientName = jobname.ClientName;
jobs.ClientId = jobname.ClientId;
jobs.JobRate = jobname.JobRate;
jobs.Status = "Active";
}
}
}
And here is my SQL Query
SELECT TOP (200) Id, Job, ClientName, ClientId, JobRate, Status
FROM Jobs
WHERE (Id = 2)
It should return some value in it.
Both inner expressions of the ifs(ones controlling item.StartDate) are identical, so your problem lies in these controls. Can you make sure your code evaluates true for below condition?
if (item.StartDate.Day.ToString() == DateTime.Now.Day.ToString())
I have this SQL query that I want to translate into Linq-to-SQL:
Now here's the beginning of the Linq-to-SQL code but I'm stuck on how to group fields and get SUM :
private void GetDatas()
{
DateTime d = DateTime.Now;
using (DataClasses1DataContext dc = new DataClasses1DataContext())
{
var query = from ent in dc.STK_ABC_ENT
join det in dc.STK_ABC_DET on ent.ENT_ID equals det.ENT_ID
join art in dc.FICHES_ARTICLES on ent.ART_CODE equals art.ART_CODE
where !ent.ENT_NUM_PAL.Contains("FDR_")
&& ent.ENT_OUTDATE == null
&& ent.ENT_PICKING == null
&& ent.ENT_DATE_ENT != d
// How to group here ?
// How to get SUM ??
}
}
You can use group x by ColumnName into z to group a column.
When you want to group multiple columns you can use group x by new { x.Column1, x.Column2 } into z.
When you want to group multiple columns in multiple tables you can use group new { x, y } by new { x.Column, y.Column } into z.
With Sum, just call it in select with lamda expression.
Example:
var query = from ent in dc.STK_ABC_ENT
join det in dc.STK_ABC_DET on ent.ENT_ID equals det.ENT_ID
join art in dc.FICHES_ARTICLES on ent.ART_CODE equals art.ART_CODE
where !ent.ENT_NUM_PAL.Contains("FDR_") && ent.ENT_OUTDATE == null
&& ent.ENT_PICKING == null && ent.ENT_DATE_ENT != d
group new { art, ent } by new {
art.ART_CODE,
...,
ent.ENT_DATE_ENT,
...
} into grouped
select new {
ArtCode = grouped.Key.ART_CODE,
SumPdsNet = grouped.Sum(x => x.DET_PNET),
...
}
I hope it can work for you.
I want to get count of a set based on different condition:
var invoices = new AccountingEntities().Transactions
var c1 = invoices.Count(i=>i.Type = 0);
var c2 = invoices.Count(i=>i.Type = 1);
var c3 = invoices.Count(i=>i.Type = 2);
How its possible to call all three queries in one DB round trip to increase performance?
Sure, just wrap up your three counts in a POCO or anonymous type:
using (var invoices = new AccountingEntities())
{
var c = (from i in invoices.Transactions
select new
{
c1 = invoices.Count(i=>i.Type = 0),
c2 = invoices.Count(i=>i.Type = 1),
c3 = invoices.Count(i=>i.Type = 2)
}).Single();
}
Also, dispose your context, as I show.
To aggregate arbitrary subqueries, use a dummy single-row result set from which you nest the desired subqueries. Assuming db represents your DbContext, the code to count invoice types will look like this:
var counts = (
from unused in db.Invoices
select new {
Count1 = db.Invoices.Count(i => i.Type == 0),
Count2 = db.Invoices.Count(i => i.Type == 1),
Count3 = db.Invoices.Count(i => i.Type == 2)
}).First();
If the want to generically get a count of all types, use grouping:
var counts =
from i in db.Invoices
group i by i.Type into g
select new { Type = g.Key, Count = g.Count() };