Getting to grips with Linq and I have a query that contains alot of joins to other tables.
I won't put the whole query here as it's not really relevant to my actual question.
I'm wondering which is the better way to write my query and why?
Query 1 :
var query = from team in context.tblTeams
join manager in context.tblManagers on team.fkManager equals manager.pkManager into managerJoin
from manager in managerJoin.DefaultIfEmpty()
join colour in context.tblTeamColours on team.fkTeamColour equals colour.pkTeamColour into colourJoin
from colour in colourJoin.DefaultIfEmpty()
join sponser in context.tblSponsers on team.fkSponser equals sponser.pkSponser into sponserJoin
from sponser in sponserJoin.DefaultIfEmpty()
select new TeamView
{
pkTeam = team.pkTeam,
strManager = manager.strManagerName,
strTeamColour = colour.strColour,
strSponser = sponser.strSponser
};
Query 2:
var query = from team in context.tblTeams
from manager in context.tblManagers.Where(x => x.pkManager == team.fkManager).DefaultIfEmpty()
from colour in context.tblTeamColours.Where(x => x.pkTeamColour == team.fkTeamColour).DefaultIfEmpty()
from sponser in context.tblSponsers.Where(x => x.pkSponser == team.fkSponser).DefaultIfEmpty()
select new TeamView
{
pkTeam = team.pkTeam,
strManager = manager.strManagerName,
strTeamColour = colour.strColour,
strSponser = sponser.strSponser
};
They both seem to take pretty much the same amount of time to run. I'm just wondering if there is any difference other than readability?
With 33 joins in the full query the second method seems neater and easier to read to me.
Alternatively, how else can I write the query which could make it faster?
Related
I have two tables:
cache and main
In cache there are a lot of fields; in main a little less. A UNION is not going to work because of the unequal number of columns.
cache
client - file - target - many other columns
main
client - file - target - few other columns
From cache I would like all columns for which main.target LIKE '%string%', cache.client = main.client, cache.file = main.file
For these particular records, target, client and file are always the same in main and cache.
I just can't get my head around this, but then again MySQL never was my strongest point.
Thank you very much in advance!
In the end combining the two SELECT statements with a UNION made things very complicated, for the simple reason there were countless other queries, some without UNION, that in the end all had to be processed by the same end routine presenting the results. As this was only a one-time query and time wasn't really an issue, in the end I just used SELECT on the two different tables and then combined the results by checking if a certain field was present. If not, the remaining results had to be fetched from the cache table; if so, the remaining results had to be fetched from the main table.
I actually wonder whether this solution is faster, slower or just as fast.
if (!isset($row['current']))
{
$field = $row['field'];
$sqlcache = "SELECT * FROM " . $dbtable . " WHERE (client = '$sqlclient' AND file = '$sqlfile' AND field = '$field')";
$resultcache = $conn->query($sqlcache);
if (!$resultcache)
{
die($conn->error);
}
$rowcache = $resultcache->fetch_assoc();
$currenttarget = $rowcache['current'];
$context = $rowcache['context'];
$dirtysource = $rowcache['dirtysource'];
$stringid = $rowcache['stringid'];
$limit = $rowcache['maxlength'];
$locked = $rowcache['locked'];
$filei = $rowcache['filei'];
}
else
{
$currenttarget = $row['current'];
$context = $row['context'];
$dirtysource = $row['dirtysource'];
$stringid = $row['stringid'];
$limit = $row['maxlength'];
$locked = $row['locked'];
$filei = $row['filei'];
}
I have few tables which are joined by some conditions.
What I am trying to achieve is Combine 2 SELECT statements in such way where
If there is data in Condition 1 display them OR go to Condition 2 and display data
Condition 1 - I am getting record from table say for exampleA, B, C and D based on some conditions
Condition 2 - I am getting record from table say for example A, B, C and E based on some conditions
What is am trying to achieve is
Display record if it exists in Condition 1
OR
Display record if it exits in Condition 2
Condition 1/ Query 1 - Display data
async getData() {
try {
const data = await this._conn.query(`
select first_name.value_name,quiz_table.answer, windows,player,first_name.value_id,country_place,current_name, pet_name, marker, relations
from schema_name.plugin,schema_name.quiz_table,schema_name.first_name, schema_name.value_version, schema_name.relationss
where plugin.answer= quiz_table.answer
and quiz_table.windows=first_name.value_id
and marker is not null
and schema_name.value_version.value_id= schema_name.first_name.value_id
and schema_name.value_version.caste= schema_name.first_name.caste
and schema_name.value_version.value_name= schema_name.first_name.value_name
and schema_name.value_version.version_number= schema_name.first_name.version_number
and schema_name.relationss.value_id= schema_name.first_name.value_id
and schema_name.relationss.caste= schema_name.first_name.caste
and schema_name.relationss.value_name= schema_name.first_name.value_name
and schema_name.relationss.version_number= schema_name.first_name.version_number
and schema_name.quiz_table.windows= schema_name.first_name.value_id
and in_process='N'
}
OR
Condition 2/ Query 2 - Display data
select schema_name.relationss."relations", schema_name.quiz_table."answer", schema_name.quiz_table."windows", schema_name.quiz_table."in_process", schema_name.quiz_table."object_name", schema_name.quiz_table."processed_date", schema_name.quiz_table."player", schema_name.quiz_table."country_place", schema_name.tools."mesh_scope_note", schema_name.plugin."current_name", schema_name.plugin."pet_name"
from schema_name.quiz_table, schema_name.tools, schema_name.plugin, schema_name.relationss, schema_name.value_version
where (in_process = 'N'
and schema_name.quiz_table."windows" = schema_name.tools."value_id"
and schema_name.quiz_table."player" = schema_name.tools."language"
and schema_name.quiz_table."answer" = schema_name.plugin."answer"
and schema_name.relationss."language" = schema_name.quiz_table."player"
and schema_name.relationss."language" = schema_name.tools."language"
and schema_name.relationss."caste" = schema_name.tools."caste"
and schema_name.relationss."value_name" = schema_name.tools."value_name"
and schema_name.relationss."version_number" = schema_name.tools."version_number"
and schema_name.relationss."value_id" = schema_name.tools."value_id"
and schema_name.value_version."value_id" = schema_name.tools."value_id"
and schema_name.value_version."version_number" = schema_name.tools."version_number"
and schema_name.value_version."caste" = schema_name.tools."caste"
)
NOTE - 1-> I cannot use function or procedure here.
2-> Both the `Conditions` contains `different data`
The problem is, how will the computer choose which option to go to? A computer does not choose, it can't. You have to provide some metric for which to choose. The boolean operator || (or) is for checking if either is true (declarative-sorta), not for imperative. You can 'ask' "is a or b true?" but you can't tell a computer, "do this or that" without any weight to either one which would explain to the computer which to pick and when.
What would be possible is asking,
"If there is data in Condition 1 display them; if not, go to Condition 2 and display data".
If that suits your needs, this is how it could be coded (this is just the framework).
if (data1 != null) {
show data1
}
else {
show data2
}
Or your data could be non-null, but have no contents, in which you could try to get some data from it (say, getChildren() (totally random, I'm just making that up):
if (data1.getChildren() != null) {
show data1
}
else {
show data2
}
I hope you know that this is just pseudocode for the theory of it. show_ is not actual code, it's just the placeholder for whatever you would write. Would this work - checking if it is null and/or checking if its contents are null (i.e., it's empty/without data) and if so then going to the next dataset?
I don't know sql, but I thought that idea of check-null/check-contents-null might help.
Using MySQL Latest Django:
I have a vaguely complex Django query that works quite quickly--until I add an additional "AND" with a Boolean Field--
See Below:
queriedForms = queryFormtype.form_set.filter(is_public=True)
newQuery = queriedForms.filter(formrecordattributevalue__record_value__icontains=term['TVAL'], formrecordattributevalue__record_attribute_type__pk=rtypePK)
newQuery = newQuery.filter(flagged_for_deletion=False)
logger.info(newQuery.query)
term['count'] = newQuery.count()
If I either remove the initial "is_public=True" or the final "flagged_for_deletion=False)--it works incredibly fast. If I use both as filters, it increases the time for the count() function by something like 2000%
The different QuerySet.query outputs are below:
SELECT `maqluengine_form`.`id`, `maqluengine_form`.`form_name`, `maqluengine_form`.`form_number`, `maqluengine_form`.`form_geojson_string`, `maqluengine_form`.`hierarchy_parent_id`, `maqluengine_form`.`is_public`, `maqluengine_form`.`project_id`, `maqluengine_form`.`date_created`, `maqluengine_form`.`created_by_id`, `maqluengine_form`.`date_last_modified`, `maqluengine_form`.`modified_by_id`, `maqluengine_form`.`sort_index`, `maqluengine_form`.`form_type_id`, `maqluengine_form`.`flagged_for_deletion` FROM `maqluengine_form` INNER JOIN `maqluengine_formrecordattributevalue` ON (`maqluengine_form`.`id` = `maqluengine_formrecordattributevalue`.`form_parent_id`) WHERE (`maqluengine_form`.`form_type_id` = 319 AND `maqluengine_form`.`is_public` = True AND `maqluengine_formrecordattributevalue`.`record_value` LIKE %seal% AND `maqluengine_formrecordattributevalue`.`record_attribute_type_id` = 18510 AND `maqluengine_form`.`flagged_for_deletion` = False)
SELECT `maqluengine_form`.`id`, `maqluengine_form`.`form_name`, `maqluengine_form`.`form_number`, `maqluengine_form`.`form_geojson_string`, `maqluengine_form`.`hierarchy_parent_id`, `maqluengine_form`.`is_public`, `maqluengine_form`.`project_id`, `maqluengine_form`.`date_created`, `maqluengine_form`.`created_by_id`, `maqluengine_form`.`date_last_modified`, `maqluengine_form`.`modified_by_id`, `maqluengine_form`.`sort_index`, `maqluengine_form`.`form_type_id`, `maqluengine_form`.`flagged_for_deletion` FROM `maqluengine_form` INNER JOIN `maqluengine_formrecordattributevalue` ON (`maqluengine_form`.`id` = `maqluengine_formrecordattributevalue`.`form_parent_id`) WHERE (`maqluengine_form`.`form_type_id` = 319 AND `maqluengine_form`.`is_public` = True AND `maqluengine_formrecordattributevalue`.`record_value` LIKE %seal% AND `maqluengine_formrecordattributevalue`.`record_attribute_type_id` = 18510)
The first takes about 20/30 seconds to perform the count(), while the second with only 1 of the two BooleanField's takes less than a second to perform the count()
=======================================
EDIT=======================
Apologies: since the question isn't obvious enough--why is adding an additional AND with a BooleanField increasing the query time by +2000%? Is anyone able to assist in figuring out WHY that's occurring. Thanks.
EDIT=========================
Also discovered that using a exclude(is_public=False) rather than filter(is_public=True) has the same effect as the solution below. Does anyone happen to know why an exclude() works fine--whereas the filter() does not?
==============================
Solution I came up with after a night's rest:
--I keep the query as is(I need it for later because it continues getting chain filtered)
--I need the count() from this stage--which is taking substantially longer than it should with the additional BooleanField AND
--I take a temporary values list to perform a len() on instead:
queriedForms = queryFormtype.form_set.all()
newQuery = queriedForms.filter(formrecordattributevalue__record_value__icontains=term['TVAL'], formrecordattributevalue__record_attribute_type__pk=rtypePK)
newQuery = newQuery.filter(flagged_for_deletion=False)
tempQuery = newQuery.values_list('is_public',flat=True)
finalQuery = [entry for entry in tempQuery if entry != 'False'] #Remove any indices that contain "False"
term['count'] = len(finalQuery)
The following counts that use chained filters after use the same technique--it's significantly faster--if not as fast as removing one of the Booleans from the filters.
I have a rather strange problem which is scratching my head at the moment. I am using EF together with MySQL for a project and when I want to update a record on the database like this
using (var context = new MyDbContext())
{
var record = (from d in context.Dictionary where d.CompanyName == companyName && d.Name == "Logo" select d).FirstOrDefault();
record.Value = _path;
context.SaveChanges();
}
Then every record that has d.Name == "Logo" gets updated for some reason, which means that it ignores the d.CompanyName == companyName part. Anyone who has experienced the same problem or know how to solve it?
Thanks in advance.
Actually I don't use EF Provider for MySQL often but I suppose it works.
The problem can be splitted in 2 parts, a select and an update. The select is fine, if you need to see what is the query you can split the select statement like this
var query = (from d in context.Dictionary where d.CompanyName == companyName && d.Name == "Logo" select d);
var record = query.FirstOrDefault();
and have a look to query variable (just point it in debug mode).
About your issue the only reason that I can immagine is that you did not configure the Dictionary class in the right way.
I mean, when you run context.SaveChanges an Update query is generated using the Key definition of Dictionary (the Where part of the query). If the key definition is wrong, the where clause will be wrong.
Use this I hope this will help you.
using (var context = new MyDbContext())
{
var record = context.Dictionary.Where(x=> x.CompanyName == companyName && x.Name == "Logo").FirstOrDefault();
record.Value = _path;
context.SaveChanges();
}
SELECT ica.CORP_ID, ica.CORP_IDB, ica.ITEM_ID, ica.ITEM_IDB,
ica.EXP_ACCT_NO, ica.SUB_ACCT_NO, ica.PAT_CHRG_NO, ica.PAT_CHRG_PRICE,
ica.TAX_JUR_ID, ica.TAX_JUR_IDB, ITEM_PROFILE.COMDTY_NAME
FROM ITEM_CORP_ACCT ica
,ITEM_PROFILE
WHERE (ica.CORP_ID = 1000)
AND (ica.CORP_IDB = 4051)
AND (ica.ITEM_ID = 1000)
AND (ica.ITEM_IDB = 4051)
AND ica.EXP_ACCT_NO = ITEM_PROFILE.EXP_ACCT_NO
I'm trying basically say since the exp account code is '801500' then the Name should return "Miscellaneous Medic...".
It seems as if what you are showing is not possible. Have you edited the data in the editor??? You are joining using ica.EXP_ACCT_NO = ITEM_PROFILE.EXP_ACCT_NO . Therefore, every entry with EXP_ACCT_NO = 801500, should also have the same COMDTY_NAME.
However, it could be the case that your IDs are not actually numbers and that they are strings with whitespace (801500__ vs 801500 ). But since you are not performing a left-outer join, it would also mean you have an entry in ITEM_PROFILE with the same whitespace.
You also need to properly normalize your table data (unless this is a view) but it still means you have erroneous data.
Try to perform the same query, but using the TRIM function to remove whitespace: https://stackoverflow.com/a/6858168/1688441 .
Example:
SELECT ica.CORP_ID, ica.CORP_IDB, ica.ITEM_ID, ica.ITEM_IDB,
ica.EXP_ACCT_NO, ica.SUB_ACCT_NO, ica.PAT_CHRG_NO, ica.PAT_CHRG_PRICE,
ica.TAX_JUR_ID, ica.TAX_JUR_IDB, ITEM_PROFILE.COMDTY_NAME
FROM ITEM_CORP_ACCT ica
,ITEM_PROFILE
WHERE (ica.CORP_ID = 1000)
AND (ica.CORP_IDB = 4051)
AND (ica.ITEM_ID = 1000)
AND (ica.ITEM_IDB = 4051)
AND trim(ica.EXP_ACCT_NO) = trim(ITEM_PROFILE.EXP_ACCT_NO);