Forcing multiple JOINs - business-objects

I have a CASE_MEMBER table with a row for each case member, and a field to indicate the member's role on the case. Let's say role 'Parent' and role 'Child'.
In the universe I've added the CASE_MEMBER table, and created a Parent object and Child object, each object containing a WHERE statement which specifies the correct value of the role field.
Now if I try and create a report with both of these objects, it will join to CASE_MEMBER only once, with a condition of "where role = 'Parent' and role = 'Child'", which is obviously impossible.
So I need to force the query to join to CASE_MEMBER once for each member type. Is the only way to do this by creating multiple aliases of CASE_MEMBER? Or is there another way to do this that also keeps my universe structure looking clean and more resembling the actual data model?

Create an alias of CASE_MEMBER, and include the WHERE condition in the join. So your joins will be:
For CASE_MEMBER to DEMOGRAPHICS:
case_member.member = demographics.memberid and case_member.role='child'
For CASE_MEMBER to DEMOGRAPHICS_PARENT (alias of DEMOGRAPHICS):
case_member.member = demographics_parent.memberid and case_member.role='parent'
Let's say you create (using the field names from your other question), a "Case ID" object from case_member.caseid, "Child SSN" from demographics.ssn, and "Parent SSN" from demographics_parent.ssn. Creating a report with all three of these objects will produce:
SELECT
case_member.caseid,
demographics.ssn,
demographics_parent.ssn
FROM
case_member,
demographics,
demographics demographics_parent
WHERE
(case_member.member = demographics.memberid
and case_member.role='child')
(and case_member.member = demographics_parent.memberid
and case_member.role='parent')
which should produce what you want.
Note that in this example, since we are including BOTH the child and parent table, we will get two rows in the result set. One with a blank child SSN and one with a blank parent SSN. To avoid this, you'd need to put a max() around each one.that

Related

Rails, MySql, JSON column which stores array of UUIDs - Need to do exact match

I have a model called lists, which has a column called item_ids. item_ids is a JSON column (MySQL) and the column contains array of UUIDs, each referring to one item.
Now when someone creates a new list, I need to search whether there is an existing list with same set of UUIDs, and I want to do this search using query itself for faster response. Also use ActiveRecord querying as much as possible.
How do i achieve this?
item_ids = ["11E85378-CFE8-39F8-89DC-7086913CFD4B", "11E85354-304C-0664-9E81-0A281BE2CA42"]
v = List.new(item_ids: item_ids)
v.save!
Now, how do I check whether a list exists which has item ids exactly matches with that mentioned in query ? Following wont work.
list_count = List.where(item_ids: item_ids).count
Edit 1
List.where("JSON_CONTAINS(item_ids, ?) ", item_ids.to_json).count
This statement works, but it counts even if only one of the item matches. Looking for exact number of items.
Edit 2
List.where("JSON_CONTAINS( item_ids, ?) and JSON_LENGTH(item_ids) = ?", item_ids.to_json, item_ids.size).count
Looks like this is working
You can implement a has many relation between lists and items and then access like this.
List.includes(:item).where('items.id in (?)',item_ids)
To implement has_many relation:
http://guides.rubyonrails.org/association_basics.html#the-has-many-through-association

Get all current joins to a query in yii2 ActiveQuery

Is there a way to get all joined table from a query?
For example:
query = Account::find()->joinWith(['gallery'])->joinWith(['articles'])->etc...
Is there any integrated method in yii2 that will return the above joined tables (or an event on which I could hook to get them manually)?
Solution suggested by #Beowulfenator shows only joins with relations (which added with joinWith() method.
To show all joins you need prepare the query like this:
$query = Account::find()
->join('...', '...')
->joinWith(['gallery', 'articles']); // By the way, you can reduce you code like this
$query->prepare();
This will transform yii\db\ActiveQuery to simple yii\db\Query which doesn't have joinWith property but has join property that shows exactly all joins.
You can var_dump and see it:
var_dump($query->join);
exit();
First element stores type of join, second - table name (note that it can be either string or array depending on used relation), third - on condition.
ActiveQuery class has joinWith public property. It's an array that contains information on all joins. It, among other things, contains joined table names.
More info here.

correctly fetch nested list in SQL

I have a design problem with SQL request:
I need to return data looking like:
listChannels:
-idChannel
name
listItems:
-data
-data
-idChannel
name
listItems:
-data
-data
The solution I have now is to send a first request:
*"SELECT * FROM Channel WHERE idUser = ..."*
and then in the loop fetching the result, I send for each raw another request to feel the nested list:
"SELECT data FROM Item WHERE idChannel = ..."
It's going to kill the app and obviously not the way to go.
I know how to use the join keyword, but it's not exactly what I want as it would return a row for each data of each listChannels with all the information of the channels.
How to solve this common problem in a clean and efficient way ?
The "SQL" way of doing this produces of table with columns idchannel, channelname, and the columns for item.
select c.idchannel, c.channelname, i.data
from channel c join
item i
on c.idchannel = i.idchannel
order by c.idchannel, i.item;
Remember that a SQL query returns a result set in the form of a table. That means that all the rows have the same columns. If you want a list of columns, then you can do an aggregation and put the items in a list:
select c.idchannel, c.channelname, group_concat(i.data) as items
from channel c join
item i
on c.idchannel = i.idchannel
group by c.idchannel, c.channelname;
The above uses MySQL syntax, but most databases support similar functionality.
SQL is made for accessing two-dimensional data tables. (There are more possibilities, but they are very complex and maybe not standardized)
So the best way to solve your problem is to use multiple requests. Please also consider using transactions, if possible.

serializing parent/child relationships with newtonsoft.json and linq to sql

I am having a problem. I have a table tblitems which has a primary key which has a child table tblweeks linked via foreign key. When using json.net to serialize json, even when the reference loop handling is set to referenceloophandling.ignore, it is serlilizing the parent tblitem class for every tblweekof linked to it. I don't want that but I still want some fields from the child class. Is there a way in my linq query to only select some columns from a child table or do I have to break the relationships? I'm confused, this seems like really unexpected behavior.
UPDATE
OK, I kind of have what I want now, I found I could use the select function on the child table to only select certain columns, but what is the best way to garentee the order of the child records? I want to make sure they are ordered by weekof in this example:
var q = from lineITem in db.tblBroadcastEntryItems
where lineITem.broadcastID == Int32.Parse(context.Request.QueryString[0])
select new
{
...,
week = lineITem.tblBroadcastEntryWeeks
.Select(c => new { c.weekof, c.spots, c.id })
};

How to do a MYSQL conditional select statement

Background
I'm faced with the following problem, relating to three tables
class_sectors table contains three categories of classes
classes table contains a list of classes students can attend
class_choices contains the first, second and third class choice of the student, for each sector. So for sector 1 Student_A has class_1 as first choihce, class_3 as second choice and class_10 as third choice for example, then for sector 2 he has another three choices, etc...
The class_choices table has these columns:
kp_choice_id | kf_personID | kf_sectorID | kf_classID | preference | assigned
I think the column names are self explanatory. preference is either 1, 2 or 3. And assigned is a boolean set to 1 once we have reviewed a student's choices and assigned them to a class.
Problem:
Writing an sql query that tells the students what class they are assigned to for each sector. If their class hasn't been assigned, it should default to show their first preference.
I have actually got this to work, but using two (very bloated??) sql queries as follows:
$choices = $db -> Q("SELECT
*, concat_ws(':', `kf_personID`, `kf_sectorID`) AS `concatids`
FROM
`class_choices`
WHERE
(`assigned` = '1')
GROUP BY
`concatids`
ORDER BY
`kf_personIDID` ASC,
`kf_sectorID` ASC;");
$choices2 = $db -> Q("SELECT
*, concat_ws(':', `kf_personID`, `kf_sectorID`) AS `concatids`
FROM
`class_choices`
WHERE
`preference` = '1'
GROUP BY
`concatids`
HAVING
`concatids` NOT IN (".iimplode($choices).")
ORDER BY
`kf_personID` ASC,
`kf_sectorID` ASC;");
if(is_array($choices2)){
$choices = array_merge($choices,$choices2);
}
Now $choices does have what I want.
But I'm sure there is a way to simplify this, merge the two SQL queries, and so it's a bit more lightweight.
Is there some kind of conditional SQL query that can do this???
Your solution uses two steps to enable you to filter the data as needed. Since you are generating a report, this is a pretty good approach even if it looks a bit more verbose than you might like.
The advantage of this approach is that it is much easier to debug and maintain, a big plus.
To improve the situation, you need to consider the data structure itself. When I look at the class_choices table, I see the following fields: kf_classID, preference, assigned which contain the key information.
For each class, the assigned field is either 0 (default) or 1 (when the class preference is assigned for the student). By default, the class with preference = 1 is the assigned one since you display it in the report when assigned=0 for all the student's class choices in a particular sector.
The data model could be improved by imposing a business rule as follows:
For preference=1 set the default value assigned=1. When the class selection process
takes place, and if the student gets assigned the 2nd or 3rd choice, then preference 1 is unassigned and the alternate choice assigned.
This means a bit more code in the application but it makes the reporting a bit easier.
The source of the difficulty is that the assignment process does not explicitly assign the 1st preference. It only updates assigned if the student cannot get the 1st choice.
In summary, your SQL is good and the improvements come from taking another look at the data model.
Hope this helps, and good luck with the work!