Hql query to filter collection data - left-join

I have a Restaurant entity with a category and a list of Branches. I want to search all the Restaurants which are in specific area and category
So, I was doing
SELECT R
FROM Restaurant AS R
LEFT JOIN R.branches AS branch
WHERE R.category.name LIKE :category AND branch.name LIKE :branch
It was working fine but it just so happens to be that, when a new restaurant is added initially the restaurant has no branches but i want to show them in result .. I am not sure how to achieve that , how to get restaurants with matching category and branch (even if it doesn't have a branch) .
If it's not clear what i am trying to do, I am trying to do something like this ..
SELECT R
FROM Restaurant AS R
LEFT JOIN R.branches AS branch
WHERE R.category.name LIKE :category AND (branch is NULL OR branch.name LIKE :branch )
retrieve those restaurants with the given branch name and also containing those that don't have any branches associated. OR in other words if Any restaurant doesn't have any branch than return it to the result list along with those matching the searched area name.

You can use extra join conditions using HQL with keyword:
SELECT R
FROM Restaurant AS R
LEFT JOIN R.branches AS branch WITH branch IS NULL OR branch.name LIKE :branch
WHERE R.category.name LIKE :category
For more information look at the documentation.

Related

Is it possible to merge two simple DB queries to get a single reply containing a hash

in my blog-like app, i have two separate queries;
Select id, title, content from posts where id ='$a_post_id'
and
Select tagname, tagscore from tags where postid ='$a_post_id'
Since my db is hosted on a different server from my app, my major performance issue is with the server request roudabout for both the queries.
I was wondering if I can merge the two queries into a single query so that the expected output is
postdetails for '$a_post_id'= id, title, content, tags (hash of tagname, tagscore)
Something similar to a join but where the rows are asymmetrical. Or join returning hashes...
Also, this sounds like a great fix to a simple issue, but am I missing something here? Assuming that this solution is possible, are there any obvioud cons associated with it?
If a JSON key/value pair is OK, you can something like this:
select p.id, p.title, p.content,
jsonb_object_agg(t.tagname, t.tagscore) as tags
from posts p
left join tags t on t.postid = p.id
where p.id ='$a_post_id'
group by p.id;
The above assumes that posts.id is defined as the primary key
Online example: https://rextester.com/RDQX27041

Filter and display database audit / changelog (activity stream)

I'm developing an application with SQLAlchemy and PostgreSQL. Users of the system modify data in 8 or so tables. Consider this contrived example schema:
I want to add visible logging to the system to record what has changed, but not necessarily how it has changed. For example: "User A modified product Foo", "User A added user B" or "User C purchased product Bar". So basically I want to store:
Who made the change
A message describing the change
Enough information to reference the object that changed, e.g. the product_id and customer_id when an order is placed, so the user can click through to that entity
I want to show each user a list of recent and relevant changes when they log in to the application (a bit like the main timeline in Facebook etc). And I want to store subscriptions, so that users can subscribe to changes, e.g. "tell me when product X is modified", or "tell me when any products in store S are modified".
I have seen the audit trigger recipe, but I'm not sure it's what I want. That audit trigger might do a good job of recording changes, but how can I quickly filter it to show recent, relevant changes to the user? Options that I'm considering:
Have one column per ID type in the log and subscription tables, with an index on each column
Use full text search, combining the ID types as a tsvector
Use an hstore or json column for the IDs, and index the contents somehow
Store references as URIs (strings) without an index, and walk over the logs in reverse date order, using application logic to filter by URI
Any insights appreciated :)
Edit It seems what I'm talking about it an activity stream. The suggestion in this answer to filter by time first is sounding pretty good.
Since the objects all use uuid for the id field, I think I'll create the activity table like this:
Have a generic reference to the target object, with a uuid column with no foreign key, and an enum column specifying the type of object it refers to.
Have an array column that stores generic uuids (maybe as text[]) of the target object and its parents (e.g. parent categories, store and organisation), and search the array for marching subscriptions. That way a subscription for a parent category can match a child in one step (denormalised).
Put a btree index on the date column, and (maybe) a GIN index on the array UUID column.
I'll probably filter by time first to reduce the amount of searching required. Later, if needed, I'll look at using GIN to index the array column (this partially answers my question "Is there a trick for indexing an hstore in a flexible way?")
Update this is working well. The SQL to fetch a timeline looks something like this:
SELECT *
FROM (
SELECT DISTINCT ON (activity.created, activity.id)
*
FROM activity
LEFT OUTER JOIN unnest(activity.object_ref) WITH ORDINALITY AS act_ref
ON true
LEFT OUTER JOIN subscription
ON subscription.object_id = act_ref.act_ref
WHERE activity.created BETWEEN :lower_date AND :upper_date
AND subscription.user_id = :user_id
ORDER BY activity.created DESC,
activity.id,
act_ref.ordinality DESC
) AS sub
WHERE sub.subscribed = true;
Joining with unnest(...) WITH ORDINALITY, ordering by ordinality, and selecting distinct on the activity ID filters out activities that have been unsubscribed from at a deeper level. If you don't need to do that, then you could avoid the unnest and just use the array containment #> operator, and no subquery:
SELECT *
FROM activity
JOIN subscription ON activity.object_ref #> subscription.object_id
WHERE subscription.user_id = :user_id
AND activity.created BETWEEN :lower_date AND :upper_date
ORDER BY activity.created DESC;
You could also join with the other object tables to get the object titles - but instead, I decided to add a title column to the activity table. This is denormalised, but it doesn't require a complex join with many tables, and it tolerates objects being deleted (which might be the action that triggered the activity logging).

changing a record to a different area

I hope yo can point me in the right direction.
I have a SSRS report organized by Continent/Country/Customer and I need to change (force?) some of the customers to appear in a different region/country from the DB. ie:
I have a local NZ customer in the right Region/Country (australasia/New Zealand) but I want this one to show up in a different Region/Country namely (Asia/China) as this customer buys locally but exports all to China.
There are some others customers that needs to be manually organized, following the same criteria, of course.
any idea on how can I do this?
and will be the best option to do it through SQL-Server or SSRS?
Thanks in advance.
Eric
I would create a new table called something like AreaOverride with the following columns:
CustomerId
Continent
Country
Then link to this in your query using a left outer join and replace the Continent and Country with the overridden values if they exist:
Select CustomerId,
Case when AreaOverride.Continent is not null then AreaOverride.Continent else Customer.Continent end as Continent,
Case when AreaOverride.Country is not null then AreaOverride.Country else Customer.Country end as Country
From Customer
Left outer join AreaOverride On AreaOverride.CustomerId = Customer.CustomerId
You might want to make this a view if you are going to use it in several reports or other places.
Then whenever you need to override a customer's details you simply add a row for them in this table and the values will be overridden in your reports.
Note that if you are dealing with a vendor database rather than your own you don't want to be messing with their database structure but you can still do this by creating a new database and put the AreaOverride table in it. Then you add the database name to your join. For example if your database was called MyStuff then your join looks like this:
Left outer join MyStuff.dbo.AreaOveride On ...

How to write a query(may be a recursive one) to fetch parent-child hierarchy in Postgresql 8.4?

I have a parent child hierarchy that is depicted as in the picture. There is one head office at the top which acts as the parent branch. The other nodes are child branches.
There can be any number of Regional zones and any number of divisional zones can be added to a Regional zone. Similarly, any number of child branches can be added to a divisional zone. Here, User login is provided at all the levels and there I'm facing a difficulty in showing only the branches that is child to the currently logged in users branch. The data base that I'm using is 'Postgresql8.4'. By Googling I found that recursion can be done. But quite frankly I didn't understand the steps followed in most of them. So can someone please help me in solving this piece of puzzle with explanation on the steps followed?
User Table
============
usr_id; //Unique id of user
usr_branch_id; //Id from the branch table
Branch Table
============
branch_id; //Unique id of branch
branch_text_id;
branch_name;
branch_parent;
you would want something like:
WITH RECURSIVE branch_tree AS (
select branch_id, branch_text_id, branch_name, branch_parent,
branch_id::text as path
from branch
where branch_parent is null
union all
select b.branch_id, b.branc_text_id, b.branch_name, b.branch_parent,
t.path || ',' || b.branch_id::text
FROM branch b
JOIN branch_tree t ON b.parent_id = t.branch_id
)
SELECT * FROM branch_tree ORDER BY string_to_array(path, ',')::int[];

products and configurable_products in postgresql

I have a Product table and a ConfigurableProduct table.
If there are several variations of the same product like a shirt in different colors I create a ConfigurableProduct.
When a user is looking at the catalog he should see a list of products unless there is a ConfigurableProduct, then he should see it with a select box for each variations.
How do I structure the tables for Product and ConfigurableProduct and how do I query the db so I can page through the results?
Thanks
I am going to answer this as if you do not have tables created. I am not sure if that is true though.
The following is a simple example, but I assume you have more data.
products
id
name
configurable_products
id
variation
product_id REFERENCES products(id)
You can just make the configurable products a reference to products.
If you want a listing of products with their configurations then you can do:
select p.name, c.variation
from products p left outer join configurable_products c
on (p.id = c.product_id);
Of course you can just search for all the configurable_products based on the product id too when needed.
As for the paging part of your question you will have to clarify what you mean. You can use limit to limit results if you don't want to get everything at once.