Count the number of rows in many to many relationships in Hibernate - spring

I have three of many tables in Oracle (10g) database as listed below. I'm using Hibernate Tools 3.2.1.GA with Spring version 3.0.2.
Product - parent table
Colour - parent table
ProductColour - join table - references colourId and prodId of Colour and Product tables respectively
Where the ProductColour is a join table between Product and Colour. As the table names imply, there is a many-to-many relationship between Product and ProductColour. I think, the relationship in the database can easily be imagined and is clear with only this much information. Therefore, I'm not going to explore this relationship at length.
One entity (row) in Product is associated with any number entities in Colour and one entity (row) in Colour can also be associated with any number of entities in Product.
Let's say as for an example, I need to count the number of rows available in the Product table (regarding Hibernate), it can be done something like the following.
Object rowCount = session.createCriteria(Product.class)
.setProjection(Projections.rowCount()).uniqueResult();
What if I need to count the number of rows available in the ProductColour table? Since, it is a many-to-many relationship, it is mapped in the Product and the Colour entity classes (POJOs) with there respective java.util.Set and no direct POJO class for the ProductColour table is available. So the preceding row-counting statement doesn't seem to work in this scenario.
Is there a precise way to count the number of rows of such a join entity in Hibernate?

I think you should be able to do a JPQL or HQL along the lines.
SELECT count(p.colors) FROM Product AS p WHERE p.name = :name ... other search criteria etc
or
SELECT count(c.products) FROM Color AS c WHERE c.name = :name .... other search criteria
From Comment below, this should work:
Long colours=(Long) session.createQuery("select count(*) as cnt from Colour colour where colour.colourId in(select colours.colourId from Product product inner join product.colours colours where product.prodId=:prodId)").setParameter("prodId", prodId).uniqueResult();

Related

Creating database view in migration laravel 5.2

I'm trying to create a database view via a migration in Laravel 5.2 as I need to hand a fairly complex query to a view. I have models / tables for leagues, teams, players, and points. Each one has a hasMany / belongsTo relationship with the one before it. The goal is to create a table where each row is a league name, a sum of all remaining points for the league, and a count of points.remnants where the value of points.remnants > 4.
Major Edit:
What I have so far is
DB::statement( 'CREATE VIEW wones AS
SELECT
leagues.name as name,
sum(points.remnants) as trem,
count(case when points.remnants < 4 then 1 end) as crem
FROM leauges
JOIN teams ON (teams.league_id = leagues.id)
JOIN players ON (players.team_id = teams.id)
JOIN points ON (points.player_id = players.id);
' );
This does not throw any errors, but it only returns one row and the sum is for all points in all leagues.
What I'm looking for is to create a table where there is a row for each league, that has league name, total remaining points for that league, and total points with less than 4 remaining per league.
Marked as solved. See the accepted answer for most of this issues. The one row problem was because I wasn't using GROUP BY with the count().
It looks to me like the problem is your SQL syntax. Here's what you wrote:
CREATE VIEW wones AS SELECT (name from leagues) AS name
join teams where (leagues.id = team.country_id)
join players where (teams.id = players.team_id)
join points where (players.id = points.player_id)
sum(points.remnants) AS trem
count(points.remnants where points.remnants < 4) AS crem
The problem is with the way you've mixed FROM and JOIN clauses with column specifications. Try this:
CREATE VIEW wones AS
SELECT
leagues.name,
sum(points.remnants) AS trem
sum(IF(points.remnants<4, 1, 0)) AS crem
FROM leagues
JOIN teams ON (leagues.id = team.country_id)
JOIN players ON (teams.id = players.team_id)
JOIN points ON (players.id = points.player_id);
I've reformatted it a bit to make it a little clearer. The SQL keywords are capitalized and the various clauses are separated onto their own lines. What we're doing here is specifying the columns, followed by the table specifications - first the leagues table, then the other tables joined to that one.

SQL Statement : Update issue

I have these three tables :
RESEARCHER(Re_Id, Re_Name, Re_Address, Re_Phone, Re_HomePhoneNumber,
Re_OfficeNumber, Re_FirstScore, Re_Second_Score)
PUBLICATION(Pub_ID, Pub_Title, Pub_Type, Pub_Publisher, Pub_Year,Pub_Country, Pub_StartingPage, Pub_Number_of_Page, Score1, Score2)
WRITTEN_BY(Re_Id, Pub_ID)
I want to change the authors of the publication “Introduction to Database System” to “Henry Gordon” and “Sarah Parker”.
The problem is in WRITTEN_BY table,I just store the researcher's ID and publication's ID.
My idea is to change the Re_Id in WRITTEN_BY by those names are "Henry Gorgon" , "Sarah Parker" , which are already existed in RESEARCHER table
UPDATE WRITTEN_BY
SET Re_Id = ....( SELECT Re_Id
FROM RESEACHER
WHERE Re_Name = ‘Henry Gordon’ OR Re_Name = ‘Sarah Paker’ )
WHERE Pub_ID IN ( SELECT Pub_ID
FROM PUBLICATION
WHERE Pub_Name = ‘Introduciton to Database system’ );
I have problem in the SET part,so how to write the SQL statement for that requirement?
Here is the sqlfiddle link for my schema : http://sqlfiddle.com/#!9/b9118/1
I'd use something like below query:
DELETE FROM WRITTEN_BY WHERE Pub_ID IN (
SELECT Pub_ID FROM PUBLICATION
WHERE Pub_Title = 'Introduciton to Database system' )
INSERT INTO WRITTEN_BY
SELECT Re_Id,Pub_Id
FROM RESEARCHER CROSS JOIN PUBLICATION
WHERE Re_Name = 'Henry Gordon' OR Re_Name = 'Sarah Paker'
AND Pub_Title like 'Introduciton to Database system'
SELECT * FROM WRITTEN_BY
The idea is to first drop the existing mapping- you should not update it- and the insert a new one.
The reason for delete/insert approach vs update in case of mapping table is justified in favor of delete/insert as most mapping tables contain many-many mapping and usually one-to-many mappings.
Initially we may have a book mapped to say n number of authors where n <>1 then we either add extra rows, or are left with extraneous rows.
See sample fiddle: http://sqlfiddle.com/#!6/a0e72/13
The real deal however is CROSS JOIN. This does not take any ON like other JOINs and is used to produce cartesian product type map.
We are restricting it to get only limited number of rows as per our need by adding suitable WHERE clauses

Linq query for one to many

My question involves MVC + Linq query. I will try to make it simple without going into the details of the Model, View, etc.. Say I have 2 tables T1 & T2. T1 holds restaurants details & T2 holds restaurants image paths. T2 rows contain restaurantID. Now if T2 has more than one rows of image paths for a Restaurant and I only need the first image path from T2 in the linq query how would I form such query? I tried to simplify the question as in fact I have 6 table joins related to the Restaurants in the query. I formed a view model which only contains the fields I want to display. I am trying to populate the view model in the controller & the query is in the controller obviously.
When I join T2 to the query, I get all the Restaurants details together with the images. But the view repeats the same Restaurant as many times as the number of table rows in T2 which is not what I want. This is the problem from the way I set the query. The query uses joins. I only need the first row from T2 while I get all from the Restaurant details. I failed to find an example for such requirement on the web so far. Your directions will be much appreciated.
Serhat Albayoglu
On your join you can use an into and then in the select you can select the FirstOrDefault
var query = from t in context.T1
join t2 in context.T2 on t.Id equals t2.RestaurantID into tgroup
select
{
t2.FirstOrDefault().path
};

Dynamics AX , items on wmslocation

New to Dynamics AX,how to get all the item in particular wmslocation and what is the relation b/w wmslocation and inventTable?
The easiest way to do this would be to create an on-hand counting journal for that WMS location.
There is no direct relation between these two tables. The item id from the inventtable can be used to connect to the inventtrans table. The inventtrans table has the itemid, transaction type (inventory transaction, transfer, item counting, etc) and the InventDimID. The InventDim table has a link to the particular dimension group you are looking for (wmslocationid).
So the SQL would look something like:
select distinct (itemid) from inventTrans where inventdimid in
(select inventDimid from inventDim
where wmslocationid = 'WMSLocationID you care about here')

Active Record Join with most recent association object attribute

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.

Resources