Combine results from two tables into one recordset - sql

I have two tables items and content.
items:|ID|menu|img
table
itemcontent |ID|parent|title|content
content holds is paired to items by parent holding the title and content
i want to search all the items and also print out those records wich do not have a title present in the itemcontent table
whereby the titles will be printed as "Empty".
so printing out the output would look something like:
title: test1 and ID: items.ID=1
title: Empty and ID: items.ID=2
title: Empty and ID: items.ID=3
title: test2 and ID: items.ID=4
title: Empty and ID: items.ID=5
etc...
I tried the following and then some but to no avail:
SELECT items.*, itemcontent.title, itemcontent.content
FROM items, itemcontent
WHERE itemcontent.title LIKE '%$search%'
AND itemcontent.parent = items.ID
order by title ASC
A little help would be much appreciated

Since you want all the rows from items whether or not they have a match in itemcontent, plus a field from itemcontent when there is a match you need to use an OUTER JOIN:
SELECT items.*, COALESCE(itemcontent.title, 'empty'), itemcontent.content
FROM items LEFT OUTER JOIN itemcontent ON itemcontent.parent = items.ID
WHERE (itemcontent.title LIKE '%$search%' OR itemcontent.title IS NULL)
ORDER BY items.ID, itemcontent.title ASC
There are small differences among SQL dialects (for instance, not all versions have COALESCE) so if you want a more precise answer indicate which product you're using.

Just to be sure you might want to ORDER BY itemcontent.title and not just title or select itemcontent.title AS title? Do you have a field called title in the items table?

Related

Sequelize Query : How to do parent and child fetch query when condition on 1 of the child is valid?

I have a parent Table "Orders" and child table "Items". They have one to many relationships. I need to do the query using the "Orders" table. I need the Items in the "include". I want to query the order which has a particular Item. But if it also has other items those too should get selected.
A toned-down version of my query looks something like this:
let term = 'phone';
Orders.findAll({
include: [
model: Item,
where: {itemName: { [Op.like]: `%${term}%` }}
]
})
The query happens but if an order has multiple items and if the item name doesn't have the 'term' in it then that particular item gets excluded. Only the item with the term is returned with the order record.
I want if the where condition is true for 1 of the items, all the other items should also get included.
For example, let's say I search for the term 'phone', I want to get the orders which looks something like the below:
Order No: 123ABC
Order Items:
Android Phone
Smart Watch
In my case, the smartwatch doesn't come with the "include" option.
I will be grateful if anyone can help me find a solution.
Thank You.
If this sql can help you..
select *
from Order o
inner join item i on i.orderId = o.id and i.itemName like %term%
inner join item i2 on i2.orderId = o.id
you can use sequelize like this!
let term = 'phone';
Orders.findAll({
include: [
{
model: Item,
as : 'searchItem',
attributes : [],
where: {itemName: { [Op.like]: `%${term}%` }},
{
model: Item,
}
]
})

Where on hasmany in sequelize with count

I am not the best at UML/database diagrams but the following hopefully shows my DB design (MsSQL)
I have a "Location" table with zero to many pallets assiociated with it (there are 0-many pallets IN a location). However that location can be one of two types, location x or y. This diagram simplifies it, but there are many different types of location, and very different fields for each type.
I am using Sequelize as an ORM, and trying to figure out how to do a particular query. I think I am close but quite stuck.
What I need is:
Select a single LocationTypeX where "active" is true, and where its corresponding Location has less than 10 pallets in it.
Previously I have gone and got all LocationTypeX where "active" is true. Included Location and Pallet (on location) and did it all in code to figure out which location is relavent. however that is taking forever, as there are thousands of Locations and loads of pallets spread out through them.
All I am after is to show the Location Name. That is it. But the Location name of one that matches the above condition. Hopefully someone can help?
So far I have
models.Location.findAll({
group: ['Location.id', 'Pallets.id'],
attributes: ['Location.id', 'Pallets.id', [models.sequelize.fn('COUNT',models.sequelize.col('Pallets.id')), 'PalletCount']],
include: [{
model: models.Pallet,
attributes: []
}]
}).then((ret)=> {
console.log(ret);
});
But this doesn't do the "active" check. And also doesn't do the where clause on the amount of pallets. Back to square one
I have managed to answer my own question with raw SQL that I can use in Sequelize. However I would still be interested to know how to do it in Sequelize
models.sequelize.query(
`SELECT TOP 1 Locations.id, Locations.name FROM LocationTypeX
INNER JOIN Locations ON LocationTypeX.LocationId = Locations.id
LEFT JOIN Pallets on (Locations.id = Pallets.LocationId)
WHERE LocationTypeX.active = 1
GROUP BY Locations.id, Locations.name
HAVING COUNT(Pallets.id) < 3`
, { type: models.sequelize.QueryTypes.SELECT})

Rails, order by number of matched tags and then by name

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.

NHibernate: how to retrieve an entity that "has" all entities with a certain predicate in Criteria

I have an Article with a Set of Category.
How can I query, using the criteria interface, for all Articles that contain all Categories with a certain Id?
This is not an "in", I need exclusively those who have all necessary categories - and others. Partial matches should not come in there.
Currently my code is failing with this desperate attempt:
var c = session.CreateCriteria<Article>("a");
if (categoryKeys.HasItems())
{
c.CreateAlias("a.Categories", "c");
foreach (var key in categoryKeys)
c.Add(Restrictions.Eq("c", key)); //bogus, I know!
}
Use the "IN" restriction, but supplement to ensure that the number of category matches is equal to the count of all the categories you're looking for to make sure that all the categories are matched and not just a subset.
For an example of what I mean, you might want to take a look at this page, especially the "Intersection" query under the "Toxi solution" heading. Replace "bookmarks" with "articles" and "tags" with "categories" to map that back to your specific problem. Here's the SQL that they show there:
SELECT b.*
FROM tagmap bt, bookmark b, tag t
WHERE bt.tag_id = t.tag_id
AND (t.name IN ('bookmark', 'webservice', 'semweb'))
AND b.id = bt.bookmark_id
GROUP BY b.id
HAVING COUNT( b.id )=3
I believe you can also represent this using a subquery that may be easier to represent with the Criteria API
SELECT Article.Id
FROM Article
INNER JOIN (
SELECT ArticleId, count(*) AS MatchingCategories
FROM ArticleCategoryMap
WHERE CategoryId IN (<list of category ids>)
GROUP BY ArticleId
) subquery ON subquery.ArticleId = EntityTable.Id
WHERE subquery.MatchingCategories = <number of category ids in list>
I'm not 100% sure, but I think query by example may be what you want.
Assuming that Article to Category is a one-to-many relationship and that the Category has a many-to-one property called Article here is a VERY dirty way of doing this (I am really not proud of this but it works)
List<long> catkeys = new List<long>() { 4, 5, 6, 7 };
if (catkeys.Count == 0)
return;
var cr = Session.CreateCriteria<Article>("article")
.CreateCriteria("Categories", "cat0")
.Add(Restrictions.Eq("cat0.Id", catkeys[0]));
if (catkeys.Count > 1)
{
for (int i = 1; i < catkeys.Count; i++)
{
cr = cr.CreateCriteria("Article", "a" + i)
.CreateCriteria("Categories", "cat" + i)
.Add(Restrictions.Eq("cat" + i + ".Id", catkeys[i]));
}
}
var results = cr.List<Article>();
What it does is to re-join the relationship over and over again guaranteeing you the AND between category Ids. It should be very slow query especially if the list of Ids gets big.
I am offering this solution as NOT a recommended way but at least you can have something working while looking for a proper one.

Linqtosql - joined rows

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.