I am looking to do the following using an NHibernate Criteria Query
I have "Product"s which has 0 to Many "Media"s
A product can be associated with 1 to Many ProductCategories
These use a table in the middled to create the join
ProductCategories
Id
Title
ProductsProductCategories
ProductCategoryId
ProductId
Products
Id
Title
ProductMedias
ProductId
MediaId
Medias
Id
MediaType
I need to implement a criteria query to return All Products in a ProductCategory and the top 1 associated Media or no media if none exists.
So although for example a "T Shirt" may have 10 Medias associated, my result should be something similar to this
Product.Id Product.Title MediaId
1 T Shirt 21
2 Shoes Null
3 Hat 43
I have tried the following solutions using JoinType.LeftOuterJoin
1) productCriteria.SetResultTransformer(Transformers.DistinctRootEntity);
This hasnt worked as the transform is done code side and as I have .SetFirstResult() and .SetMaxResults() for paging purposes it wont work.
2) .SetProjection(
Projections.Distinct(
Projections.ProjectionList()
.Add(Projections.Alias(Projections.Property("Id"), "Id"))
...
.SetResultTransformer(Transformers.AliasToBean());
This hasn't worked as I cannot seem to populate a value for Medias.Id in the projections. (Similar to nHibernate Criteria API Projections)
Any help would be greatly appreciated
Related
Suppose I have many tagged entities (e.g. blog posts with tags) to store in a SQL database. For example:
post1: work
post2: work, programming, java, work
post3: work, programming, sql
post4: vacation, photo
post5: vacation
post6: photo
Suppose also I have a list of tags
work, vacation
Now I'd like to get a posts sample of size 2, i.e. two posts with tags from the list. For example
sample1: post1 and post2
sample2: post1 and post4
sample3: post2 and post5
In addition I'd like the sample to contain all tags in the list. Note that sample1 does not meet this requirement since the set of tags of the sample entities does not contain tag vacation from the list.
I would like also all tags occurrences to be equal. Let's consider 2 samples of size 4.
sample1: post1, post2, post3, post6
sample2: post1, post3, post4, post5
Note that sample1 does not meet this requirement since tag work occurs 3 times in it and vacation occurs only once.
My question is: how to design a relational database and SQL query to retrieve samples of given size?
If you want to get all posts that have tags in a comma delimited list:
select postid
from post_tags
where find_in_set(tagid, #LIST) > 0
group by postid
having count(distinct tagid) = 1+length(#LIST) - length(replace(',', #LIST, ''));
If you want just a "sample" of them:
select postid
from (select postid
from post_tags
where find_in_set(tagid, #LIST) > 0
group by postid
having count(distinct tagid) = 1+length(#LIST) - length(replace(',', #LIST, ''))
) t
order by rand()
limit 5
I am trying to query the Product Manufacturer in Magento 1.7.0.2 . I browse again and again all the table to where I can get the manufacturer table and connect it with product SKU.
I try this query to hope that I can get the manufacturers of the product:
SELECT
eav_attribute_option_value.value FROM
eav_attribute,
eav_attribute_option,
eav_attribute_option_value
WHERE
eav_attribute.attribute_code = 'manufacturer' AND
eav_attribute_option.attribute_id = eav_attribute.attribute_id AND
eav_attribute_option_value.option_id = eav_attribute_option.option_id
but it is not equal to the product manufacturer when I compare the result to my magento admin product manufacturer.
My question is that what should I do to query so that I can get the list of manufacturers of the product so that I can sql join in with catalog_product_enity's SKU.
Does anyone has an idea about my case? I am new with magento so please be gentle with me.
Any help will be appreciated, Thanks in advance
I hope I understood correctly.
If you want to get the manufacturer for a product, you don't need any query.
This should work. Let's assume that you already have the product in var $_product;
$_product->getAttributeText('manufacturer');//this gets you the label
$_product->getManufacturer(); //gets the manufacturer id
[EDIT]
To get this for all the products do this:
$collection = Mage::getModel('catalog/product')->getCollection()
->addAttributeToSelect('manufacturer');
$collection->addAttributeToFilter('status', 1);//optional for only enabled products
$collection->addAttributeToFilter('visibility', 4);//optional for products only visible in catalog and search
foreach ($collection as $product) {
$sku = $product->getSku();
$manufacturerId = $product->getManufacturer();
$manufacturerLabel = $product->getAttributeText('manufacturer');
//do something with the values above - like write them in a csv or excel
}
Little late, but this is what I came up with. Works like a charm.
SELECT cpe.sku, cpev.value, cpf1.manufacturer_value
FROM catalog_product_entity cpe
JOIN catalog_product_entity_varchar cpev ON cpev.entity_id = cpe.entity_id
JOIN catalog_product_flat_1 cpf1 ON cpf1.entity_id = cpe.entity_id
WHERE cpev.attribute_id = 191
Here's what I want to do: Listing has a many-to-many relationship with Tag through Taggings. I want to allow a user to search for listings by title (of the listing) and name (of zero or more tags). I want to order the number of results first by the listings with the greatest number of tags matched, and then by title.
It seems like this question has been done before -- it might be as simple as matching this question (Ordering items with matching tags by number of tags that match) from MySQL. However, I'm not SQL-literate at all, which is why I'm asking for help.
Update:
Here is an example of what I want.
Say I have 3 listings.
listing1 has tags "humor," "funny," and "hilarious."
listing2 = 2 has tags "funny," "silly," and "goofy."
listing3 = 3 has tags "funny," "silly," and "goofy."
listing4 = 4 has the tag "completely serious."
If I make a search with the tags "funny" and "silly", what I should get back is listing2, listing3, listing1, and listing4 (ignoring titles for now).
Interesting problem. I think you might have to use some SQL sugar to do this scope.
Something like this:
Listing
.joins("LEFT JOIN taggings ON taggings.listing_id = listings.id")
.joins('LEFT JOIN tags ON tags.id = taggings.tag_id AND tags.name IN ("funny","silly")')
.group(:id)
.order("count(tags.id), name DESC")
Does that help?
Assuming you want a solution in pure ActiveRecord so as not to touch any SQL...
Listing.order("tags.count DESC, title")
In this case you'd probably be better off using a counter cache for tags to optimize your queries.
I have been having a problem with the Rails 3 Active Record Query Interface. I have a lookup table (lookups), a Main table (through_references), and a through/join table called through_tables. Thus this is a HABTM configuration that I have set up using has_many :through.
Update: Of special note here is that when I am doing these joins, I have been joining on IDs, to provide filtering of records. It seems that this does not work with Active Record Query Interface. If you do not want to see the gory details of my travails, you can skip down to see my workaround below.
We are also going to have a number of Main Items (through_references table) should be able to have any combination of lookup items, and to conveniently be able to click the relevant lookup items say through check boxes.
I have posted the code on github. There is quite a lot more explanations on the github source code. to see the results, go to the lookups index page. Note that you will need to create the records using the scaffold code.
I also have the code up and running on heroku, with more explanations and examples.
class Lookup < ActiveRecord::Base
has_many :fk_references
has_many :through_tables
has_many :through_references, :through => :through_tables
attr_accessible :name, :value
end
class ThroughTable < ActiveRecord::Base
belongs_to :through_reference
belongs_to :lookup
attr_accessible :description, :through_reference_id, :lookup_id
end
class ThroughReference < ActiveRecord::Base
has_many :through_tables
has_many :lookups, :through => :through_tables
attr_accessible :description
end
If we want to have a listing if all the lookup items, and the Main Items that correspond with them, we can LEFT JOIN the ‘lookups’ table with the Main Items (through_references) table.
Corresponding SQL:
SELECT * FROM lookups
LEFT OUTER JOIN through_tables ON (lookups.id = through_tables.lookup_id AND through_tables.through_reference_id = 1)
LEFT OUTER JOIN through_references ON through_references.id = through_tables.through_reference_id
ORDER BY lookups.id
Returned records:
1;“Lookup Item 1”;“1”;“2012-06-06 17:14:40.819791”;“2012-06-06 17:14:40.819791”;1;1;1;“Main Item 1 has Lookup item 1”;“2012-06-06 17:17:31.355425”;“2012-06-06 17:17:31.355425”;1;“Main Item 1”;“2012-06-06 17:16:30.004375”;“2012-06-06 17:16:30.004375”
2;“Lookup Item 2”;“2”;“2012-06-06 17:14:59.584756”;“2012-06-06 17:14:59.584756”;;;;“”;“”;“”;;“”;“”;“”
3;“Lookup Item 3”;“3”;“2012-06-06 17:15:14.700239”;“2012-06-06 17:15:14.700239”;2;1;3;“Main Item 1 has Lookup item 3”;“2012-06-06 17:17:53.169715”;“2012-06-06 17:17:53.169715”;1;“Main Item 1”;“2012-06-06 17:16:30.004375”;“2012-06-06 17:16:30.004375”
This is what I expected.
=== Active Record Query Interface using custom left join
Lookup.joins(“LEFT OUTER JOIN through_tables ON (lookups.id = through_tables.lookup_id AND through_tables.through_reference_id = 1)” ).includes(:through_references).order(‘lookups.id’)
What is returned from Active Record Query Interface (note I navigate down through the Active Record hierarchy):
Lookup ID Lookup Name Lookup Value Through Table ID Through Table Description Main Item ID Main Item Description
1 Lookup Item 1 1 1 Main Item 1 has Lookup item 1 1 Main Item 1
1 Lookup Item 1 1 3 Main Item 2 has Lookup item 1 2 Main Item 2
2 Lookup Item 2 2 4 Main Item 2 has Lookup item 2 2 Main Item 2
3 Lookup Item 3 3 2 Main Item 1 has Lookup item 3 1 Main Item 1
This is NOT what I expected.
What we have here is identical to the simple left join (without the AND clause). This tells me that the AND clause is being ignored in the Active Record Query Interface.
=== Active Record Query Interface using find_by_sql approach
Lookup.find_by_sql("SELECT * FROM lookups LEFT OUTER JOIN through_tables ON (through_tables.lookup_id = lookups.id AND through_tables.through_reference_id = 1) LEFT OUTER JOIN through_references ON through_references.id = through_tables.through_reference_id ORDER BY lookups.value, through_references.id" )
What is returned from Active Record Query Interface (note I navigate down through the Active Record hierarchy)::
Lookup ID Lookup Name Lookup Value Through Table ID Through Table Description Main Item ID Main Item Description
1 Lookup Item 1 1 3 Main Item 2 has Lookup item 1 2 Main Item 2
1 Lookup Item 1 1 1 Main Item 1 has Lookup item 1 1 Main Item 1
Lookup Item 2 2 No through_tables entry
1 Lookup Item 3 3 3 Main Item 2 has Lookup item 1 2 Main Item 2
1 Lookup Item 3 3 1 Main Item 1 has Lookup item 1 1 Main Item 1
The results here are crazy!
Is this a BUG, is this the intended effects, or am I missing something ?
I hope there is a clean way of doing this, without having to generate two result sets, and merge them by code.
I have found a work-around. The issue seems to be that Active Record will not recognize joins that filter on an ID (LEFT OUTER JOIN xyz ON xyz.id = ID).
My work-around involves creating a stored procedure or function that takes the ID in as a parameter, does the join in the Database, and returns a nice flat recordset.
see: Heroku demo page (skip to bottom)
Note, I am not marking this as a solution, because this is a work-around, and nothing to do with active record.
Well, reading the github project, I see this:
What I really want to do is have a list of all of the lookup items,
and if there are matching Main Items, have them appended on to the
returned record, and if not, I want nulls. This is a technique that I
have used for over 10 years.
I'm thinking that problem is exactly that you want to do it that way, when it would be more natural to let rails eager loading handle it, and so you've gotten fixated on fetching everything in a single massive join.
What I would do is something like:
Lookup.where( .. insert any needed conditions here ...).includes(:through_tables)
Then ActiveQuery will then fetch all the Lookup in one query, and then use eager loading to fetch any associations named in the includes statement, one query per association.
Note I'm not saying that joins are bad, just saying that this is a more natural way to do it in rails. I like to use the Preloader http://apidock.com/rails/ActiveRecord/Associations/Preloader to separate out the decision about what to eager load from the decision about which data to fetch. I find that helpful in controllers - let the model decide what the conditions are, but let the controller decide which objects it'll need to eager load.
HTH
In Linqtosql how do I show items from multiple rows in a single field.
eg I have a 3 table setup for tagging(entity, tag, entitytag) all linked via foreign keys.
For each entity I would like to return the name in one field and then all relevant tags in 2nd field.
eg Item1, tag1; tag2; tag3
Item2, tag4, tag5....
VB statements preferred.
Thanks
Geoff
Okay, not sure if this is the most efficient way but it works.
Dim dc As New DataContext
Dim query = From i In dc.Items _
Let tags = (From t In dc.ItemTags _
Where t.ItemID = i.ID _
Select t.Tag.Name).ToArray _
Select i.ItemName, Tags = String.Join(" | ", tags)
With this answer I am assuming you have your tables setup similar to the following, names are not great, just for illustration:
AnEntity: Id, Name
ATag: Id, TagName
EntityTag: EntityId (FK to AnEntity.Id), TagId (FK to ATag.Id)
You might try this:
var entityTags = from ent in theEntities
from enttags in ent.EntityTags
group enttags by enttags.AnEntity into entityGroup
select new { TheEntity = entityGroup.Key, TheTags =
from t in entityGroup
select t.ATag.TagName };
I have not been able to actually test this, I'll give it a shot this afternoon and edit it if need be. What is happening here is a SelectMany. The 'from ent in dc.AnEntities' gets all of the entity records, then the next 'from enttags in ent.EntityTags' gets all the entity tag records for each entity. The group by does pretty much that, groups the EntityTag records by AnEntity. Put them in an anonymous type and you are good to go.
EDITED:
Okay, changed the code above, it works now. Before you would get a list of the EntityTag objects, now you get the Entiy object and a list of strings (tags) for that entity.