I have 3 tables
1 Advertiser
2 Adverts
id
Advertiser can have multiple adverts
3 instances
id
ad_id
date
Adverts can have multiple date - date is the column in instances table
$input = Input::get('fullname'); // fullname is the id of adverstiser
// input is the advertiser id
$adverts = DB::table('adverts')->where('a_id',$input)->get();
return view('adverts.index', compact( 'adverts'));
This query will give me all adverts data related to advertiser.
fine with that.
in my adverts.index
#foreach($adverts as $advert)
<div class="caption">
<ul>
<li><i class="fa fa-picture-o"></i> {{$advert->height}}x{{$advert->height}}</li>
<li><i class="fa fa-file"></i> {{$advert->finfo}}</li>
<li><i class="fa fa-eye"></i> Last seen:</li>
<li><i class="fa fa-link"></i> {{$advert->domain}}</li>
<li><i class="fa fa-link"></i> Visit full ad</li>
</ul>
</div>
#endforeach
I would like to get the last seen date from the instance table.
SELECT MAX(date) AS "Last seen date" FROM instances WHERE ad_id =1
ad_id is the primary key id from adverts table
I would like to pass the value of this query to them same view as above
adverts.index
Is the loop must be done in view?
Or something else I am missing.
I would first see if you can get the maximum date for each advert that has at least one corresponding instance. Something like this should do the trick:
$instances = DB::table('instances')
->select(DB::raw('*, MAX(date) as last_seen_date'))
->groupBy('ad_id')
->get();
If you can get this to work first, then you can join it with your advertiser and adverts tables to match a particular advertiser and get the remaining information for each advert. You can also do a leftJoin to ensure that you grab all adverts, even ones that don't have any matching instances.
I would also strongly encourage you to define models, which will make it easier to create reusable query fragments ("scopes") throughout your application.
Related
i have two tables
women-dress
women-dress_attributes
women-dress has price , color and women-dress_attributes has display_name , attribute_name and filter
filter is a simple Y or N value
a row in women-dress_attributes looks like
Price price Y
since price has a filter value of Y i need to load distinct price values from women-dress
a part of my controller looks like this
$Filter_query = DB::table($attribute_table_name)
->select('display_name','attribute')
->where('filter', '=', 'Y')
->get();
and inside my blade file i have
#foreach($Filter_query as $agm)
<h4>{{ $agm->display_name }}</h4>
#endforeach
now how can i run another sql select distinct query to load the corresponding value inside the blade file?
or is there any better practice?
The proper way to do this in laravel is to create a model for each of your 2 tables, and create a relationship fucntion (i.e.dress()) between them.
Then you will be able to call in your blade this $agm->dress()->price to get the price.
Read this for creating models
And this for creating relationships between your models
I need to show a list of partners and the maximum value from the reservation_limit column from Klass table.
Partner has_many :klasses
Klass belongs_to :partner
# Partner controller
def index
#partners = Partner.includes(:klasses)
end
# view
<% #partners.each do |partner| %>
Up to <%= partner.klasses.maximum("reservation_limit") %> visits per month
<% end %>
Unfortunately the query below runs for every single Partner.
SELECT MAX("klasses"."reservation_limit") FROM "klasses" WHERE "klasses"."partner_id" = $1 [["partner_id", 1]]
If there are 40 partners then the query will run 40 times. How do I optimize this?
edit: Looks like there's a limit method in rails so I'm changing the limit in question to reservation_limit to prevent confusion.
You can use two forms of SQL to efficiently retrieve this information, and I'm assuming here that you want a result for a partner even where there is no klass record for it
The first is:
select partners.*,
max(klasses.limit) as max_klasses_limit
from partners
left join klasses on klasses.partner_id = partners.id
group by partner.id
Some RDBMSs require that you use "group by partner.*", though, which is potentially expensive in terms of the required sort and the possibility of it spilling to disk.
On the other hand you can add a clause such as:
having("max(klasses.limit) > ?", 3)
... to efficiently filter the partners by their value of maximum klass.limit
The other is:
select partners.*,
(Select max(klasses.limit)
from klasses
where klasses.partner_id = partners.id) as max_klasses_limit
from partners
The second one does not rely on a group by, and in some RDBMSs may be effectively transformed internally to the first form, but may execute less efficiently by the subquery being executed once per row in the partners table (which would stil be much faster than the raw Rails way of actually submitting a query per row).
The Rails ActiveRecord forms of these would be:
Partner.joins("left join klasses on klasses.partner_id = partners.id").
select("partners.*, max(klasses.limit) as max_klasses_limit").
group(:id)
... and ...
Partner.select("partners.*, (select max(klasses.limit)
from klasses
where klasses.partner_id = partners.id) as max_klasses_limit")
Which of these is actually the most efficient is probably going to depend on the RDBMS and even the RDBMS version.
If you don't need a result when there is no klass for the partner, or there is always guaranteed to be one, then:
Partner.joins(:klasses).
select("partners.*, max(klasses.limit) as max_klasses_limit").
group(:id)
Either way, you can then reference
partner.max_klasses_limit
Your initial query brings all the information you need. You only need to work with it as you would work with a regular array of objects.
Change
Up to <%= partner.klasses.maximum("reservation_limit") %> visits per month
to
Up to <%= partner.klasses.empty? ? 0 : partner.klasses.max_by { |k| k.reservation_limit }.reservation_limit %> visits per month
What maximum("reservation_limit") does it to trigger an Active Record query SELECT MAX.... But you don't need this, as you already have all the information you need to process the maximum in your array.
Note
Using .count on an Active Record result will trigger an extra SELECT COUNT... query!
Using .length will not.
It generally helps if you start writing the query in pure SQL and then extract it into ActiveRecord or Arel code.
ActiveRecord is powerful, but it tends to force you to write highly inefficient queries as soon as you derail from the standard CRUD operations.
Here's your query
Partner
.select('partners.*, (SELECT MAX(klasses.reservation_limit) FROM klasses WHERE klasses.partner_id = partners.id) AS maximum_limit')
.joins(:klasses).group('partners.id')
It is a single query, with a subquery. However the subquery is optimized to run only once as it can be parsed ahead and it doesn't run N+1 times.
The code above fetches all the partners, joins them with the klasses records and thanks to the join it can compute the aggregate maximum. Since the join effectively creates a cartesian product of the records, you then need to group by the partners.id (which in fact is required in any case by the MAX aggregate function).
The key here is the AS maximum_limit that will assign a new attribute to the Partner instances returned with the value of the count.
partners = Partner.select ...
partners.each do |partner|
puts partner.maximum_limit
end
This will return max. limits in one select for an array of parthner_ids:
parthner_ids = #partners.map{|p| p.id}
data = Klass.select('MAX("limit") as limit', 'partner_id').where(partner_id: parthner_ids).group('partner_id')
#limits = data.to_a.group_by{|d| d.id}
You can now integrate it into your view:
<% #partners.each do |partner| %>
Up to <%= #limits[partner.id].limit %> visits per month
<% end %>
I thought this would be fairly easy to find an answer to, but I'm at a loss after looking here, W3Schools and asp.net.
I'd like to display the added total of a sql column on as cshtml website. It's a charity event where people signup and give an amount they are going to pledge. I basically want to say:
<h2>"Total Raised So Far!"</h2>
<div>sum of the Pledge column from the Players table</div>
I'm currently displaying all of the people registered and their pledges using the following code:
#{
var db = Database.Open("BBBT");
var selectQueryString = "SELECT * FROM Players ORDER BY Team";
}
snip
<table>
<thead>
<tr>
<th>Team</th>
<th>First Name</th>
<th>Last Name</th>
<th>Pledge</th>
</tr>
#foreach(var row in db.Query(selectQueryString)){
<tr>
<td>#row.Team</td>
<td>#row.FName</td>
<td>#row.LName</td>
<td>$#row.Pledge</td>
</tr>
}
Any help would be greatly appreciated!
The easiest way since you are already fetching all the rows that you want is to calculate the sum from the results of the query. So i would expand the code slightly. The line with the sum and the arrow in it uses Linq technology.
#{
var db = Database.Open("BBBT");
var selectQueryString = "SELECT * FROM Players ORDER BY Team";
var results = db.Query( selectQueryString );
int SumOfPledges = 0;
SumOfPledges = results.Sum( x => x.Pledge);
}
and then in the html below, exactly what you have except for the loop
#foreach(var row in results){
and finally adding where you would like it, either above or below the loop but after the code:
<h1>Total Pledges: #SumOfPledges</h1>
Now I made the SumOfPledges an int which means integer like whole numbers. If it can have fractional numbers in it, you might need to make it a double or decimal. The type needs to match what's in the database.
SELECT sum(pledge)
FROM Players
GROUP BY Team
ORDER BY Team
Hope this is what you are trying to do.
I have this set of tables (I'm using postgresql)
User (with id, first_name, ....)
Assignment (with id, name, start_date, finish_date,....)
AssignmentUser(with assignment_id, user_id, flag_status)
The flag_status is a boolean that says if a user is still or not in an assignment.
Let's say user1 applies for assignment1, assignment2, assignment3 as follows:
start_date finish_date flag_status
user1 assignment1 11-11-11 11-12-11 false
user1 assignment2 01-10-11 01-02-12 true
user1 assignment3 01-01-12 01-03-12 true
Let's say I want to search TODAY the closest start_date of an user's assignment.
I've done this in my User model:
def last_date
self.assignments.where("date < ?", Date.today).max.try(:date)
end
and this
def last_status
AssignmentUser.find_by_assignment_id_and_user_id(Assignment.find_by_date(self.last_date), self.id).flag_status if self.last_date.present?
end
And in my view for each user:
User.all.each do |u|
<td> u.first_name </td>
<td> u.last_date </td>
<td> u.last_status </td>
end
It works well but, in my log I see 3 queries for each user (as expected).
So my question is: how can I avoid these multiple queries? (I guess it's more like a SQL question than a Rails one)
#au = AssignmentUsers.find_by_sql(
"SELECT assignment_users.user_id, MAX(assignment_users.date) as last_date,
assignment_id,
assignments.flag_status,
users.first_name
FROM assignment_users
LEFT JOIN assignments
ON assignments.id = assignment_id
LEFT JOIN users
ON users.id = user_id
WHERE date < CURDATE()
GROUP BY user_id;"
)
Then in your view:
#au.each do |u|
<tr>
<td> u.first_name </td>
<td> u.last_date </td>
<td> u.last_status </td>
</tr>
end
PLEASE NOTE: this is iterating over AssignmentUsers, so if there are any users who are without an assignment they will be missed. IF that isn't good enough (i.e. you don't want to pull back a 2nd list - easily done by User.all(:conditions => "id NOT IN (#{#au.collect(&:user_id}) - then this solution isn't suitable and if that's the case, then i think you're already probably doing it the best way, although i would have changed your methods to scopes - if you want me to show you how that would look let me know.
I'm trying to write a custom SQL query that will create a list of the most recent Posts AND comments and I'm having trouble visualizing how i can do this.
I can pull the latest comments by date DESC and i can pull the latest posts by date DESC but how do I make a feed / query to show them both?
Here is my comment SQL
SELECT comment_id, comment_content, comment_date
FROM wp_comments
WHERE comment_author = 'admin'
ORDER BY comment_date DESC
Edit: more clear:
Sorry, I should have been a little more clear. I want to have a list like this based on what date they occurred:
Wordpress post
wordpress post
wordpress comment
wordpress post
wordpress comment
So if someone comments on a 4 month old post, it will still show up at the top of this 'feed'
To get a list based solely on the most recent timestamp from two tables, you need to use a UNION:
SELECT wc.comment_date AS dt
FROM WP_COMMENTS wc
UNION ALL
SELECT wp.post_date AS dt
FROM WP_POSTS wp
ORDER BY dt
...where dt is the column alias for the column that holds the date value for records in either table.
Use UNION ALL - because data is from two different tables, there's no change of duplicates to filter out. But that means you have to get the other columns you want from either table to line up based on data and data type...
I think your best bet (and to avoid using custom SQL) would be to grab the latest X posts and X comments, loop over each and build an array to merge the two into one 'most recent' data set;
$comments = get_comments('number=X');
$posts = get_posts('posts_per_page=X');
$most_recent = array();
foreach ($comments as $comment)
$most_recent[strtotime($comment->comment_date_gmt)] = $comment;
foreach ($posts as $post)
$most_recent[strtotime($post->post_date_gmt)] = $post;
unset($comments, $posts);
krsort($most_recent);
$most_recent = array_slice($most_recent, 0, X);
foreach ($most_recent as $post_or_comment) {
$is_post = isset($post_or_comment->post_date_gmt);
// output comments and posts
}
It ain't too pretty, but it should do it.
No special mySql necessary, just use the query_posts loop and the get_comments function in the loop.
<?php query_posts('posts_per_page=10'); while (have_posts()) : the_post(); ?>
<div>
<a href="<?php the_permalink() ?>" title="Permanent Link to <?php the_title_attribute(); ?>"<?php the_title_attribute(); ?></a>
<?php echo the_title(); ?>
<?php
$comments = get_comments();
foreach($comments as $comm) :
echo($comm->comment_author);
echo($comm->comment_content);
endforeach;
?>
</div>
<?php endwhile; ?>