I have a Contact model which has many Notes. On one page of my app, I show several attributes of a table of contacts (name, email, latest note created_at).
For the note column, I'm trying to write a joins statement that grabs all contacts along with just their latest note (or even just the created_at of it
What I've come up with is incorrect as it limits and orders the contacts, not their notes:
current_user.contacts.joins(:notes).limit(1).order('created_at DESC')
If you just want the created_at value for the most recent note for each contact, you can first create a query to find the max value and then join with that query:
max_times = Note.group(:contact_id).select("contact_id, MAX(created_at) AS note_created_at").to_sql
current_user.contacts.select("contacts.*, note_created_at").joins("LEFT JOIN (#{max_times}) max_times ON contacts.id = max_times.contact_id")
If you want to work with the Note object for the most recent notes, one option would be to select the notes and group them by the contact_id. Then you can read them out of the hash as you work with each Contact.
max_times = Note.group(:contact_id).select("contact_id, MAX(created_at) AS note_created_at").to_sql
max_notes = Note.select("DISTINCT ON (notes.contact_id) notes.*").joins("INNER JOIN (#{max_times}) max_times ON notes.contact_id = max_times.contact_id AND notes.created_at = note_created_at").where(contact_id: current_user.contact_ids)
max_notes.group_by(&:contact_id)
This uses DISTINCT ON to drop dups in case two notes have exactly the same contact_id and created_at values. If you aren't using PostgreSQL you'll need another way to deal with dups.
Related
I'm developing a functionality that fills a collection, using two select lists, with a shuttle . I'm not getting the correct way to display the name, and recover its correspondent id, on shuttle's select item at right side, when I change an specific list, after repeated interventions. I developed a procedure to update, insert or delete the selected items on shuttle, and I suppose its works well after several tests on sql commands.
My test case uses three tables : contracts, worksations and employees. I intend to insert the employees of any workstation of a given contract to another contract. That new contract, whose will receive the employees, must have its owns workstations, previously inserted. The general structure of the tables is:
contracts : pk_contract, number_contract, company_name etc...
workstations : pk_workstation, fk_contract, description etc...
employees: pk_employee, fk_workstation, employee_name, employee_sex etc...
I created an app to demonstrate it: https://apex.oracle.com/pls/apex/f?p=43921
USER: test,
PASSWORD : TEST
Page 2- Migrate Employees - has three major regions, and 2 another to display information inserted :
Contracts with a select list, that must choice, preferrable the contract 070/2016, witch have workstation inserted, and a display field with static value, representing a contract, with workstations and employees attached.
workstations: with two select list, the gordian knot, I suppose : old workstations, related original contract's wokstations - related to display field, at contract's region; and new workstation, related to new contract selected above.
Employees: with a shuttle that represents, at left side, a bunch of employees, of a given original workstation and button witch do nothing.
Two more regions representing a classical report, only to inform the inserted, updated or deleted employees, from shuttles right size, using a collection. I made two report's regions because don't know make joins with collections and tables. This collection have the employee id, old_workstation id, new_workstation id, and new contract id, for further migration, not yet implemented.
I'm submiting almost all the fields, for recover its values on apex session's state.
Apparently, the collection works well, with a procedure, but when I choose again the original worksation the shuttle don't display, on right size, the previous inserted employee on that workstation. I configured on my list of values to not include extra values, when i change it, it shows the employee's ids, not their names, regards to source type listed here below:
SELECT e.pk_employee
FROM tb_employee e
INNER JOIN tb_workstation pt
ON pt.pk_workstation = e.fk_workstation
WHERE pt.typo IS NOT NULL
AND e.fk_workstation = p2_original_workstation
AND e.pk_employee IN (
SELECT to_number(c001) AS id_employee
FROM apex_collections
WHERE collection_name = 'WORKSTATION_EMPLOYEES');
My shutlle's lov has this rationale:
SELECT e.name, e.pk_employee
FROM tb_employee e
INNER JOIN tb_workstation pt
ON pt.pk_workstation = e.fk_workstation
WHERE pt.typo IS NOT NULL
AND e.fk_workstation = p2_original_workstation
AND e.pk_employee NOT IN (
SELECT to_number(c001) AS id_employee
FROM apex_collections
WHERE collection_name = 'WORKSTATION_EMPLOYEES');
Could anyone help me on this issue?
Regards!
I consider this a regular and fine solution. The shuttle permits recover entire registers on left side, changing it to another original workstation. After have removed the last "and" subclause, added at SHUTTLE an source sql query - return colon separated value, like this:
select e.pk_employee from employee e
inner join workstations w on w.pk_workstation = e.fk_workstation
where w.typo is not null and e.fk_workstation = :P2_ORIGINAL_WORKSTATION and e.pk_employee in (
SELECT TO_NUMBER(c001) as id_employee FROM APEX_collections WHERE collection_name = 'WORKSTATION_EMPLOYEES' and c002 = :P2_NEW_WORKSTATION);
But for purpose of goood usabilty, and my better interpretation that what shuttle obect does, I reinsert the 'and' clause with an 'and' more, reflecting that on lov has all employees of a given original workstation, except by the employees also inserted and that ones became from another new workstations. This particularité avoids the user thinks that a employee previously attached, on new workstation needed to be inserted:
select e.name, e.employee from employees e
inner join workstations w on w.pk_workstation = e.workstation
where w.typo is not null and e.worktation = :P2_ORIGINAL_WORKSTATION and e.pk_employee not in (
SELECT TO_NUMBER(c001) as id_employee FROM APEX_collections WHERE collection_name = 'WORKSTATION_EMPLOYEES' and c002 != :P2_NEW_WORKSTATION)
I could be consider use without these cited subclauses, using a disable jquery, in case of same original_wrkstion but at a diferent new, at left size, however its will be an improvement, and I need to understand the jqueries features. I consider this an basic and good, yet functional solution.
TablePatient.Patient_ID(PK)
TableProviders.Encounter (joins to PK)
TableProviders.Provider_Type
TableProviders.Provider_ID
TableNames.Full_Name
TableNames.Provider_ID (joins to Table Names)
I want a query that will give, for all the Patient_IDs, the Full_Name of the provider for every Provider ID.
There are about 30 provider_types.
I have made this already using a left join a ton of left joins. It takes a long time to run and I am thinking there is a trick I am missing.
Any help?
Ok, my previous answer didn't match at all what you meant. You want to pivot the table to have on each line one Patient_ID with every Full_name for every provider_type. I assume that each patient has only one provider for one type and not more ; if more, you will have more than one row for each patient, and anyway I don't think it's really possible.
Here is my solution with pivot. The first part is to make it more understandable, so I create a table named TABLE_PATIENT in a subquery.
WITH TABLE_PATIENT AS
(
SELECT TablePatient.Patient_ID,
TableProviders.Provider_Type,
TableNames.Full_Name
FROM TablePatient LEFT JOIN
TableProviders on TablePatient.Patient_ID = TableProviders.Encounter
LEFT JOIN
TableNames on TableNames.Provider_ID = TableProviders.Provider_ID
group by TablePatient.Patient_ID,
TableProviders.Provider_Type,
TableNames.Full_Name
)
SELECT *
FROM TABLE_PATIENT
PIVOT
(
min(Full_name)
for Provider_type in ([type1], [type2],[type3])
) AS PVT
So TABLE_PATIENT just has many rows for each patient, with one provider each row, and the pivot puts everything on a single row. Tell me if something doesn't work.
You need to write every type you want in the [type1],[type2] etc. Just put them inside [], no other character needed as ' or anything else.
If you put only some types, then the query will not show providers of other types.
Tell me if something doesn't work.
If I understand what you mean, you just want to group the answer by Patient Id and then Provider ID. A full name is unique on a provider id right ?
This should be something like
SELECT TablePatient.Patient_ID,
TableProviders.Provider_ID,
TableNames.Full_Name
FROM TablePatient LEFT JOIN
TableProviders on TablePatient.Patient_ID = TableProviders.Encounter
LEFT JOIN
TableNames on TableNames.Provider_ID = TablerProviders.Provider_ID
group by TablePatient.Patient_ID,
TableProviders.Provider_ID,
TableNames.Full_Name
You can either group by TableNames.Full_Name or select First(TableNames.Full_Name) for example if indeed a full name is unique to a provider ID.
Note : I used the SQL server Syntax, there can be différences with Oracle ..
I am trying to get all records from an entity that do not join to another entity.
This is what I am trying to do in SQL:
SELECT * from table1
LEFT join table2
ON table1.code = table2.code
WHERE table2.code IS NULL
It results in all table1 rows that did not join to table2.
I have it working with Linq when joining on one field, but I have contact records to join on firstname, dob, and number.
I have a "staging" entity that is imported to; a workflow processes the staging records and creates contacts if they are new.
The staging entity is pretty much a copy of the real entity.
var queryable = from staging in linq.mdo_staging_contactSet
join contact in linq.ContactSet
on staging.mdo_code equals contact.mdo_code
into contactGroup
from contact in contactGroup.DefaultIfEmpty()
// all staging records are selected, even if I put a where clause here
select new Contact
{
// import sequence number is set to null if the staging contact joined to the default contact, which has in id of null
ImportSequenceNumber = (contactContactId == null) ? new int?(subImportNo) : null,
/* other fields get populated */
};
return queryable // This is all staging Contacts, the below expressions product only the new Contacts
.AsEnumerable() // Cannot use the below query on IQuerable
.Where(contact => contact.ImportSequenceNumber != null); // ImportSequenceNumber is null for existing Contacts, and not null for new Contacts
Can I do the same thing using method syntax?
Can I do the above and join on multiple fields?
The alternatives I found were worse and involved using newRecords.Except(existingRecords), but with IEnumerables; is there a better way?
You can do the same thing with method calls, but some tend to find it harder to read since there are some LAMBDA expressions in the middle. Here is an example that shows how the two are basically the same.
I've seen others ask this same questions and it boils down to choice by the developer. I personally like the LINQ approach since I also write a bunch of SQL and I can read the code easier.
I have user with name, location, created_at as important fields in table.
I want to retrieve for each user the latest location,i.e, I want something like this:
username location created_at
abc New York 2012-08-18 16:18:57
xyz Mexico city 2012-08-18 16:18:57
abc Atlanta 2012-08-11 16:18:57
only input is UId(1,2) array of userids.please help me to accomplish this.I just want to know how to write query using active record query interface.
Generally, this should be a standard way to solve this kind of problems:
SELECT l1.user, l1.location
FROM locations l1
LEFT JOIN locations l2 ON l1.user = l2.user AND l2.created_at > l1.created_at
WHERE l2.id IS NULL
The idea is to join the table with itself, and find those rows which don't have any row with the same user and greater created_at.
Of course, you should have (user, created_at) index on your table.
Now you should see how would that be represented in AR interface.
When
u_id
is the array of user ids, then
u_id.map{|i| User.find(i).location}
should be an array of the users locations.
You can Use
User.where(:uid => [1,2,3]).maximum('location')
which will create something like
SELECT MAX(`users`.`location`) AS max_id FROM `users` WHERE `users`.`id` IN (1, 2,3)
i'm in a situation my mind is blocked en hope someone can help me.
I have two tables. One table with customers of a subsription service and one invoice table.
these tables are not linked with keys in the database for keeping history of invoices if customers are deleted. This way I have to query the customers table joining the invoiceheader table by another unique contraint (not know by the database). This constraint is using name and address together.
An invoice is send one time a year. In the invoice-header table the date is stored when the invoice is created. In a couple of years constomers can have multiple invoices.
i'm trying to create a linq query but i'm looking the wrong way for a solution I'm afraid.
who can point me the right way?
for now i have a query :
var temp = from c in context.customer
from i in context.invoiceheader
where c.name + c.address == i.name + i.address
&& i.invoicedate < DateTime.Now.Year
select c;
With this query I get all customers who have receive an invoice last year and stil have subscribed. The trouble is with new customers who never received an invoice.
What to do for customers where in this case they haven't any invoice records.?
summurized: I want to query the last know invoice. If this invoice is older than a year (previous year)or no invoice is sent at al, i wanna retreive a list of customers the should be sent a new invoice.
I guess that what you want is a left outer join - this way you should be able to get all the customers you need:
var customers = from c in context.customer
join i in context.invoiceheader
on c.Name + c.Address equals i.Name + i.Address
into g
from row in g.DefaultIfEmpty()
where row == null ||row.invoicedate < DateTime.Now.Year
select c;