Having trouble transcribing mySQL query in peewee - mysql

I have a query in mySQL that produces desired output when entered into the mySQL terminal, however, I'm having trouble trying to write the same query in the Peewee ORM.
Here is the mySQL query:
select t.PATH, s.PATH from media_data as t
left outer join media_data as s on
s.SHOW = t.SHOW and s.EPISODE = t.EPISODE and s.SHOT = t.SHOT and s.FRAME = t.FRAME and t.LABEL_TYPE = 'target'
where s.LABEL_TYPE = 'source' and s.SHOW = 'doc_d' and s.EPISODE = '102'
union
select t.PATH, s.PATH from media_data as t
right outer join media_data as s on
s.SHOW = t.SHOW and s.EPISODE = t.EPISODE and s.SHOT = t.SHOT and s.FRAME = t.FRAME and t.LABEL_TYPE = 'target'
where s.LABEL_TYPE = 'source' and s.SHOW = 'doc_d' and s.EPISODE = '102';
And here is my attempt at the corresponding peewee query
s = media_data.alias()
t = media_data.alias()
predicate = (s.SHOW == t.SHOW and s.EPISODE == t.EPISODE and s.SHOT == t.SHOT
and s.FRAME == t.FRAME and t.LABEL_TYPE == 'target')
query = media_data.select(s.PATH, t.PATH).join(t, join_type=JOIN.FULL_OUTER, on=predicate).where(s.LABEL_TYPE == 'source' and s.SHOW == show and s.EPISODE == episode)
When I try to run python, it tells me there's a problem with 'JOIN.FULL_OUTER' even though it is used exactly as defined in the syntax.

There are a couple issues. First you need to use & instead of and in your predicates and to use parentheses to properly bind these:
predicate = ((S.show == T.show) &
(S.episode == T.episode) &
(S.shot == T.shot) &
(S.frame == T.frame) &
(T.label_type == 'target'))
Additionally, if your database is complaining about full outer join, perhaps it does not support this type of JOIN (and hence the reason for the awkward UNION query)?
If you have confirmed that your database does support full outer join, then the following should work:
T = MediaData.alias()
predicate = ((MediaData.show == T.show) &
(MediaData.episode == T.episode) &
(MediaData.shot == T.shot) &
(MediaData.frame == T.frame) &
(T.label_type == 'target'))
query = (MediaData
.select(MediaData.path, T.path)
.join(T, join_type=JOIN.FULL_OUTER, on=predicate)
.where(
(MediaData.label_type == 'source') &
(MediaData.show == 'doc_d') &
(MediaData.episode == '102')))
Query:
SELECT "t1"."path", "t2"."path"
FROM "mediadata" AS "t1"
FULL OUTER JOIN "mediadata" AS "t2" ON (
("t2"."show" = "t1"."show") AND
("t2"."episode" = "t1"."episode") AND
("t2"."shot" = "t1"."shot") AND
("t2"."frame" = "t1"."frame") AND
("t2"."label_type" = 'target'))
WHERE (
("t1"."label_type" = 'source') AND
("t1"."show" = 'doc_d')) AND
("t1"."episode" = '102'))

Related

MYSQL: select where / and / or with two tables

I am trying to get the following SQl working:
SELECT * FROM tc_appointment as tcAppointment, tc_message as tcMessage
WHERE tcAppointment.counsellor_id = 502
AND
(
(tcAppointment.tc_message_id = tcMessage.id AND tcMessage.marked_read = false AND tcMessage.sender_id != 502)
OR
(tcAppointment.cancelled = true AND tcAppointment.cancelled_acknowledged = false)
OR
(tcAppointment.confirmed = false)
);
The tcAppointment.tc_message_id is null in the only tc_appointment entry in the table. I am trying to get it to return as the counsellor_id = 502 and the second OR statment is true
I seem to be getting stuck because of the tc_message as tcMessage clause and the first AND / OR statement but I'm not sure why. Can anyone point me in the right direction please?
Try Joining the 2 tables and use the 'Where':
SELECT * FROM tc_appointment as tcAppointment
LEFT JOIN tc_message as tcMessage
ON
((tcAppointment.tc_message_id = tcMessage.id AND tcMessage.marked_read = false AND tcMessage.sender_id != 502)
OR
(tcAppointment.cancelled = true AND tcAppointment.cancelled_acknowledged = false)
OR
(tcAppointment.confirmed = false)
)
WHERE tcAppointment.counsellor_id = 502

How toPerform a left join in linq pad -

How can I get linq pad to run my left join as show below?
var query =
from s in db.CDBLogsHeaders
.OrderByDescending(g => g.LogDateTime)
from sc in db.StyleColors
.Where(stylecolor => stylecolor.id == (int?)s.StyleColorID)
.DefaultIfEmpty()
from c in db.StyleHeaders
.Where(styleHeader => styleHeader.id == (int?)s.StyleHeaderID)
.DefaultIfEmpty()
select new
{
CDBLogsHeaderId = s.Id,
Merchandiser = c.Merchandiser,
Material = s.Material,
Season = s.Season,
LogsHeaderLogType = s.LogType,
PushFromTo = s.PushFromTo,
LinePlan = s.LinePlan,
QuikRefNumber = s.QuikRefNumber,
PLMOrigin = s.PLM_Origin,
SeasonOriginal = c.SeasonOriginal,
SeasonCurrent = c.SeasonCurrent,
StyleHeaderId = c.Id,
StyleCode = c.StyleCode,
StyleColorsColorCode = sc.ColorCode
};
query.Dump();
The sql that linq pad creates runs perfectly in Management Studio but linq-pad doesn't display any rows and gives this error
InvalidOperationException: The null value cannot be assigned to a
member with type System.Int32 which is a non-nullable value type.
How can I get linqpad to work so I can play with it?
In your anonymous type, make sure your ints are returning ints.
Change
StyleHeaderId = c.Id,
To
StyleHeaderId = (c.Id == null ? 0 : c.Id),

LINQ Take syntax

I have written some LINQ to simulate an SQL GroupBy statement (see below). However, I also need to only consider only the last 10 settingIds before doing my group by. I think I would use Take to do this, but what would be the correct syntax in my statement?
var settings2 = from s in dc.SystemSettings
where s.campConfig.campaignType == campType
&& s.campId != campId
&& s.settingKey == ticket.setting.Key
orderby s.settingId descending
group s by s.settingValue
into grp
select new
{
SettingValue = grp.Key,
SettingCount = grp.Select(x => x.settingValue).Count()
};
I would do something like this
var settings2 = from sOuter in
(from s in dc.SystemSettings
where s.campConfig.campaignType == campType
&& s.campId != campId
&& s.settingKey == ticket.setting.Key
orderby s.settingId descending
select s).Take(10)
group sOuter by sOuter.settingValue
into grp
select new
{
SettingValue = grp.Key,
SettingCount = grp.Select(x => x.settingValue).Count()
};

"ERROR: Only one expression can be specified in the select list" Linq To Sql

var loggedInHours = db.LoginLogs.Where(l => l.UserId == u.Id && l.UserSessionStop != null)
.Sum(ls=> ls.UserSessionStart.Subtract(ls.UserSessionStop.Value).Hours)
I am trying to calculate Total LoggedIn Hours using this linq query..
But its giving me this error
"Only one expression can be specified in the select list when the subquery is not introduced with EXISTS."
I don't know whats wrong with it..plz help
Try if this works:
var loggedInHours = db.LoginLogs.Where(l => l.UserId == u.Id && l.UserSessionStop != null)
.Select(l=> new {
StartTime = l.UserSessionStart,
EndTime = l.UserSessionStop
})
.ToList()
.Sum(c=> c.StartTime - c.EndTime);
btw, Is UserSessionStop nullable? If yes, then what will be the value to be subtracted?

LINQ to SQL Query Where Clause

I would like to create a single query that "adjusts" it's where clause based on a tuple. The first item in the tuple contains a enum value indicating the field in which to filter. The second tuple item is the filter value.
Notice the query below does not work:
var query = from p in db.Categories
where ( QueryBy.Item1 == CategoryFields.Name && p.Name == (string)(QueryBy.Item2) ) ||
( QueryBy.Item1 == CategoryFields.Id && p.Id == (long)(QueryBy.Item2) ) ||
( QueryBy.Item1 == CategoryFields.Description && p.Description == (string)(QueryBy.Item2) ) ||
( QueryBy.Item1 == CategoryFields.SortOrder && p.SortOrder == (int)(QueryBy.Item2) )
select...
if (query.Count() == 1) // ERRORS HERE CONVERSION OF INT
A similar query with only this where clause change will works:
var query = from p in db.Categories
where ( QueryBy.Item1 == CategoryFields.Name && p.Name == (string)(QueryBy.Item2) )
select...
if (query.Count() == 1) // Works HERE
Any idea what could be wrong? Can it be that LINQ where clause perform a short-circuit evaluation and thus the cast of item2 fails? Is there a better way to accomplish my overall goal of adjusting where clause?
Thanks in advance for your help!
LINQ to SQL isn't smart enough to optimize your query and generate it dynamically based on the value of your QueryBy.Item1. It will simply generate a SQL query let SQL server decide this for itself.
When you know that, the error makes sense, since it's impossible for one single value to be castable to both int, long, and string.
In your case you would be better of dynamically generating the right where clause. You can do this with the PredicateBuilder:
IQueryable<Category> query = db.Categories;
var whereClause = PredicateBuilder.False<Category>();
switch (QueryBy.Item1)
{
case CategoryFields.Name:
long id = (string)QueryBy.Item2;
whereClause = whereClause.Or(p => p.Name == name);
break;
case CategoryFields.Id:
string name = (string)QueryBy.Item2;
whereClause = whereClause.Or(p => p.Id == id);
break;
case CategoryFields.Description:
string des = (string)QueryBy.Item2;
whereClause =
whereClause.Or(p => p.Description == des);
break;
case CategoryFields.Id:
string sort = (int)QueryBy.Item2;
whereClause =
whereClause.Or(p => p.SortOrder == sort);
break;
}
query = query.Where(whereClause);