How can I order a query by a related field? - yii

Using Yii 1.1.15 assume I have a model:
State(id,name) ----- 1<>N ----- City(id,state_id,name)
#the only relevant field in each is `name`, having City the
#corresponding FK field to State.
And want to query cities sorted (asc) by State Name, and then (asc) by City name.
City::model()->with('state')->findAll(array('order' => 'name ASC'));
How do I alter the sort criteria to consider the state name?
(footnote: in other frameworks like Python/Django I'd do City.objects.select_related('state').order_by('state__name', 'name') - i.e. many frameworks have support for a nested ordering - does Yii have as well?)

USe this
City::model()->with(array('with'=>array(
'state'=>array(
'alias'=>'v',
'order'=>'t.name ASC',
)
))->findAll();

Related

list fields of latest version of each record

I have two tables like below for versioning,
application table only stores static fields (fields that will never change, in this case only the id of application). And application_version table stores the dynamic fields (fields that might change in the future, like it can be renamed etc.) and every time there is a change, a new row is being added to the application_version table. (Here is a more detailed explanation of this type of versioning design.)
application
--------------------
id (PK)
created_at
...
application_version
--------------------
id (PK)
name
description
version
application_id (FK)
...
So i'd like to list name, description etc. of all the applications last version.
I'm just able to list max versions of each application:
SELECT max(version) FROM application_version GROUP BY application_id
How do i make the mentioned query.
In PostgreSQL you can use DISTINCT ON. DISTINCT ON keeps the first row for each grouping, according to the ORDER BY clause.
For example:
select distinct on (application_id) *
from application_version
order by application_id, version desc
See running example at db<>fiddle.

How to represent a tree structure with ORDER BY OR GROUP BY

Given a table 'TEMPLATES'(with columns ID,NAME,IS_MASTER,MASTER_ID etc) which describes multiple content management system elements e.g. masters, templates etc.
The column IS_MASTER filters the master-docs. I want to filter all master-docs and the associated elements(documents), which point to the master over the 'MASTER_ID' column of the same table but I want to order the rows one after another for example after a result row which shows a master should be listed the elements, which point to this master (and not all rows mixed up like in the screenshot) :
But I can only do it in this way, I don't know how to order or group by
SELECT x.*,x.ROWID FROM TEMPLATE x
WHERE IS_MASTER IN (1) OR MASTER_ID IS NOT NULL
You could do this:
select *
from templates
order by nvl(master_id, id);
This would tell the database to sort by master_id, and if that column is empty (NULL) to use the id. This way the master and its children are sorted together.
Alternatively you can use a hierarchical query:
select *
from templates
start with master_id is null
connect by master_id = prior id;

Return one result for each search value

How can I return a unique value based on a set of non unique values being searched?
For example:
If I wanted to return one phone number for a list of 4 people who can have more than one phone number - but I can only use one phone number for each person. It doesn't matter which phone number I use to reach them because any number that belongs to them will get me to them.
I don't think something like this exists - but if I could use something like the DISTINCT modifier except it would be called FIRST - it would solve my problem:
SELECT FIRST ID
FROM Sample_Table
WHERE ID in ("Bob", "Sam", "Kyle", "Jordan")
In picture - from this
I'd like that (or any) query to return
.
I'm using this type of query in a db where for 200 "ID"s there are millions of "Unique Values", so it is hard to get crafty.
EDIT The Unique value in my db has numbers and letters in each value
There is no such thing as a "first id" in a SQL table. Tables represent unordered sets. You can accomplish what you want (if I understand correctly) using aggregation:
SELECT ID, MIN(UniqueValue)
FROM Sample_Table
WHERE ID in ('Bob', 'Sam', 'Kyle', 'Jordan')
GROUP BY ID;
using group by and max method can help you:
select id
,uniquvalue
,max (typeofvalue)
from Sample_Table
group by
id
,uniquvalue

how to make relation between two foreign key values of two tables in Yii

I have the database just like this
==== cis_policy_registration====
id
policy_id
email_id
policy_start_date
==== cis_policy_family_details===
id
policy_id
is_main_applicant
firstname
lastname
gender
Now how to make the relation between models with the policy_id (both tables),
I want to take firstname and lastname in registration model and check is main applicant
that must list in CGridView
who can solve this problem
thanks in advance
The relation between these two tables should be handled from the "main" model (Policy), so in Policy model class you should have:
'policy_reg' => array(self::HAS_ONE, 'PolicyRegistration', 'policy_id'),
'policy_details' => array(self::HAS_ONE, 'PolicyDetails', 'policy_id'),
And then:
$policy = Policy::model()->with(array('policy_details'))->findByPk($pk);
$policy->policy_details->is_main_applicant;
...
And in CGridView you can print the relational value like this (after sending CActiveDataProvider object from Policy model):
'policy_details.firstname'
or
array(
'name'=>'Firstname',
'value'=>'$data->policy_details->firstname',
),

Insert into table some values which are selected from other table

I have my database structure like this ::
Database structure ::
ATT_table- ActID(PK), assignedtoID(FK), assignedbyID(FK), Env_ID(FK), Product_ID(FK), project_ID(FK), Status
Product_table - Product_ID(PK), Product_name
Project_Table- Project_ID(PK), Project_Name
Environment_Table- Env_ID(PK), Env_Name
Employee_Table- Employee_ID(PK), Name
Employee_Product_projectMapping_Table -Emp_ID(FK), Project_ID(FK), Product_ID(FK)
Product_EnvMapping_Table - Product_ID(FK), Env_ID(FK)
I want to insert values in ATT_Table. Now in that table I have some columns like assignedtoID, assignedbyID, envID, ProductID, project_ID which are FK in this table but primary key in other tables they are simply numbers).
Now when I am inputting data from the user I am taking that in form of string like a user enters Name (Employee_Table), product_Name (Product_table) and not ID directly. So I want to first let the user enter the name (of Employee or product or Project or Env) and then value of its primary key (Emp_ID, product_ID, project_ID, Env_ID) are picked up and then they are inserted into ATT_table in place of assignedtoID, assignedbyID, envID, ProductID, project_ID.
Please note that assignedtoID, assignedbyID are referenced from Emp_ID in Employee_Table.
How to do this ? I have got something like this but its not working ::
INSERT INTO ATT_TABLE(Assigned_To_ID,Assigned_By_ID,Env_ID,Product_ID,Project_ID)
VALUES (A, B, Env_Table.Env_ID, Product_Table.Product_ID, Project_Table.Project_ID)
SELECT Employee_Table.Emp_ID AS A,Employee_Table.Emp_ID AS B, Env_Table.Env_ID, Project_Table.Project_ID, Product_Table.Product_ID
FROM Employee_Table, Env_Table, Product_Table, Project_Table
WHERE Employee_Table.F_Name= "Shantanu" or Employee_Table.F_Name= "Kapil" or Env_Table.Env_Name= "SAT11A" or Product_Table.Product_Name = "ABC" or Project_Table.Project_Name = "Project1";
The way this is handled is by using drop down select lists. The list consists of (at least) two columns: one holds the Id's teh database works with, the other(s) store the strings the user sees. Like
1, "CA", "Canada"
2, "USA", 'United States"
...
The user sees
CA | Canada
USA| United States
...
The value that gets stored in the database is 1, 2, ... whatever row the user selected.
You can never rely on the exact, correct input of users. Sooner or later they will make typo's.
I extend my answer, based on your remark.
The problem with the given solution (get the Id's from the parent tables by JOINing all those parent tables together by the entered text and combining those with a number of AND's) is that as soon as one given parameter has a typo, you will get not a single record back. Imagine the consequences when the real F_name of the employee is "Shant*anu*" and the user entered "Shant*aun*".
The best way to cope with this is to get those Id's one by one from the parent tables. Suppose some FK's have a NOT NULL constraint. You can check if the F_name is filled in and inform the user when he didn't fill that field. Suppose the user eneterd "Shant*aun*" as name, the program will not warn the user, as something is filled in. But that is not the check the database will do, because the NOT NULL constraints are defined on the Id's (FK). When you get the Id's one by one from the parent tables. You can verify if they are NOT NULL or not. When the text is filled in, like "Shant*aun*", but the returned Id is NULL, you can inform the user of a problem and let him correct his input: "No employee by the name 'Shantaun' could be found."
SELECT $Emp_ID_A = Emp_ID
FROM Employee_Table
WHERE F_Name= "Shantanu"
SELECT $Emp_ID_B = Emp_ID
FROM Employee_Table
WHERE B.F_Name= "Kapil"
SELECT $Env_ID = Env_ID
FROM Env_Table
WHERE Env_Table.Env_Name= "SAT11A"
SELECT $Product_ID = Product_ID
FROM Product_Table
WHERE Product_Table.Product_Name = "ABC"
SELECT $Project_ID = Project_ID
FROM Project_Table
WHERE Project_Name = "Project1"
Please use AND instead of OR.
INSERT INTO ATT_TABLE(Assigned_To_ID,Assigned_By_ID,Env_ID,Product_ID,Project_ID)
SELECT A.Emp_ID, B.Emp_ID, Env_Table.Env_ID, Project_Table.Project_ID, Product_Table.Product_ID
FROM Employee_Table A, Employee_Table B, Env_Table, Product_Table, Project_Table
WHERE A.F_Name= "Shantanu"
AND B.F_Name= "Kapil"
AND Env_Table.Env_Name= "SAT11A"
AND Product_Table.Product_Name = "ABC"
AND Project_Table.Project_Name = "Project1";
But it is best practice to use drop down list in your scenario, i guess.