Multiple conditions in mySQL - mysql

I want to filter the products on the basis of price, brand, and category. But none of them is required. So the user can filter the products on the basis of only price or price and brand. How to write this in mySQL using queries only. I have searched a lot but found the solution with the help of Stored Procedures.
If I write this query select * from product where brandid = 1 AND price = 10 and categoryid = 5. it will fetch 2 products which satisfy the where clause.
But if user doesn't want to filter the product on the basis of brand (lets say), then what will b the query? select * from product where brandid = null AND price = 10 and categoryid = 5... this will not work as I dont want to search products with brandid null. What I want is to remove that particular clause from where condition. So what my expected query is select * from product where price = 10 and categoryid = 5

Construct the query incrementally. Here it is in Ruby (since you didn't tag a programming language), but the logic is quite language-independent.
query = "SELECT * FROM products"
filters = []
params = []
if price_min
filters << "price >= ?"
params << price_min
end
if price_max
filters << "price <= ?"
params << price_max
end
if brand
filters << "brand = ?"
params << brand
end
# ...
unless filters.empty?
query += " WHERE " + filters.join(' AND ')
end

Related

database query to get lowest price based on last crawel date

I would like to get lowest price of product based on last crawled dates by various resellers. My current function is very basic, it gets me lowest price from table without considering reseller ids and crawled timestamps.
I've rough idea that we can SELECT * FROM "custom_data_table" and process the data using php. Please have a look at attachment for further clarification.
function get_lowest_price($table_id) {
global $wpdb;
$table_prices = $wpdb->get_results(
$wpdb->prepare(
"SELECT price FROM `custom_data_table` WHERE tableid= %d"
,$table_id)
);
if (!empty($table_prices) && $table_prices !== NULL)
return rtrim(min($table_prices)->price, '00');
}
The right query here is:
SELECT price
FROM custom_data_name cdn, (
SELECT MAX(crawled) AS maxCrawled, resellerid
FROM custom_data_name
GROUP BY resellerid
) cdnFiltered
WHERE cdn.crawled = cdnFiltered.maxCrawled AND
cdn.resellerid = cdnFiltered.resellerid AND
tableid = %d;
Try this:
SELECT B.price
FROM (SELECT resellerid, MAX(crawled) max_crawled
FROM custom_data_table
GROUP BY resellerid) A
JOIN custom_data_table B
ON A.resellerid=B.resellerid AND A.max_crawled=B.crawled;
Maybe use ORDER BY crawled and LIMIT 1

Group by one column and sum by another

Trying to write rake task that contains a query that will group by one value on a join table and then sum another column. I'd like to do it using the query interface. Purpose of this task is to find the videos that have been the most popular over the last 5 days.
In pertinent part:
course_ids = Course.where(school_id: priority_schools).pluck(:id)
sections = Section.where(course_id: course_ids)
sections.each do |section|
users = section.users.select {|user| user.time_watched > 0}
user_ids = []
users.each { |user| user_ids << user.id }
user_videos = UserVideo.group(:video_id).
select(:id, :video_id, :time_watched).
where("created_at > ?", Date.today - 5.days).
where(user_id: user_ids).sum(:time_watched)
p "user_videos: #{user_videos.inspect}"
end
Any suggestions for the how / the best way to write this query?

Selecting all records that begin with the a particular letter

I am trying to create a mySQL statement that will select all records that begin with a particular letter.
For example, select all product names that being with letter 'A'.
This is what I would like the results set to be like:
result[0] = "Awesome Bracelets";
result[1] = "Abalone Earrings";
result[2] = "Aloe Gel";
result[3] = "Amscot Figure";
I would not want the following result to be included:
result[3] = "Basic Ashtray";
This is what I tried, though it seems to return mixed results where some of the prod_name records do not have any words that start with an 'A':
"SELECT * FROM products WHERE prod_name LIKE '%A'"
I appreciate any help with this.
You are almost right
"SELECT * FROM products WHERE prod_name LIKE 'A%'"

Convert this code into active record/sql query

I have the following code and would like to convert the request into a mysql query. Right now I achieve the desired result using a manual .select (array method) on the data. This should be possibile with a single query (correct me if I am wrong).
Current code:
def self.active_companies(zip_code = nil)
if !zip_code
query = Company.locatable.not_deleted
else
query = Company.locatable.not_deleted.where("zip_code = ?", zip_code)
end
query.select do |company|
company.company_active?
end
end
# Check if the company can be considered as active
def company_active?(min_orders = 5, last_order_days_ago = 15)
if orders.count >= min_orders &&
orders.last.created_at >= last_order_days_ago.days.ago &&
active
return true
else
return false
end
end
Explanation:
I want to find out which companies are active. We have a company model and an orders model.
Data:
Company:
active
orders (associated orders)
Orders:
created_at
I don't know if it is possible to make the company_active? predicate a single SQL query, but I can offer an alternative:
If you do:
query = Company.locatable.not_deleted.includes(:orders)
All of the relevant orders will be loaded into the memory for future processing.
This will eliminate all the queries except for 2:
One to get the companies, and one to get all their associated orders.

Simple mySQL subqueries

I have a simple problem, but I am new to SQL so please forgive my ignorance.
I have a accounting report that figures out balances oweing and adds up the balances to report to me what the total outstanding are within a specific period. The issue is for every JOB there are many invoices that provide a running total/balance, because of this when my current query adds up the balances it shows me outstanding amounts that are sky high, we have found that the current code is adding the balances of all the invoices.
Example-
If JOB ID 001 has four invoices-
I-001 balance 200,
I-002 balance 100,
I-003 balance 50,
I-004 balance 0.
It will show me that there is $350 outstanding when in fact it is zero.
The solution that I can think of(which I am not sure how to code) are to group the results by job ID and use the MAX feature to select only the higest ID for every JOBID
The problem I am having is that the balances are not saved to the table but recalculated every time they are needed. What can you suggest to show me only the balance from the highest Invoice ID for a particular JOBID
My invoice table has the following columns:
1 ID int(11)
2 ParentID int(11)
3 JOBID varchar(100)
4 DATE date
5 LENSES decimal(10,2)
6 FRAMES decimal(10,2)
7 TAXABLEGOODS decimal(10,2)
8 DISCOUNT decimal(10,2)
9 PREVIOUSBALANCE decimal(10,2)
10 PAYMENT decimal(10,2)
11 PAYMENTTYPE varchar(200)
12 NOTES varchar(255)
13 PMA decimal(10,2)
The current code looks like this:
$pieces = explode("-", $_REQUEST["STARTDATE"]);
$startDate=$pieces[2] . "-" . $pieces[1] . "-" . $pieces[0];
if($_REQUEST["ENDDATE"]==""){
$endDate=0;
}else{
$pieces = explode("-", $_REQUEST["ENDDATE"]);
$endDate = $pieces[2] . "-" . $pieces[1] . "-" . $pieces[0];
}
$result = mysql_query("SELECT * FROM INVOICES WHERE DATE BETWEEN '" . $startDate . "' AND '" . $endDate . "'");
$totalCount = 0;
$total = 0;
$allPayments= 0;
$pmtTypes = Array();
$totalHST = 0;
$outstanding=0;
$payments=0;
while($theRow=mysql_fetch_array($result)){
$allPayments += $theRow["PAYMENT"];
if($theRow["PAYMENTTYPE"] == "") $theRow["PAYMENTTYPE"] = "BLANK";
if(isset($pmtTypes[$theRow["PAYMENTTYPE"]])){
$pmtTypes[$theRow["PAYMENTTYPE"]] += $theRow["PAYMENT"];;
}else{
$pmtTypes[$theRow["PAYMENTTYPE"]] = $theRow["PAYMENT"];;
}
if($theRow["PREVIOUSBALANCE"] != 0) continue;
$subTotal = ( ( $theRow["LENSES"] + $theRow["FRAMES"] + $theRow["TAXABLEGOODS"] ) - $theRow["DISCOUNT"]);
$HST = ( $theRow["TAXABLEGOODS"] * 0.13 );
$totalHST+= $HST;
$total += ( $subTotal + $HST );
$payments+=$theRow["PAYMENT"];
}
$outstanding=$total-$payments;
Anyone have anything to contribute?
I would appreciate any help.
show me only the balance from the highest Invoice ID for a particular JOBID
For a single job ID:
SELECT lenses+frames+taxablegoods-discount+previousbalance AS balance
FROM invoices WHERE jobid=?
ORDER BY id DESC LIMIT 1
group the results by job ID and use the MAX feature to select only the higest ID for every JOBID
If you want to query the latest invoice for many jobs at once, you are talking about a per-group-maximum selection. SQL doesn't make this as easy to do as you'd hope. There are various approaches, including subqueries, but on MySQL I typically favour the null-self-join:
SELECT i0.jobid, i0.lenses+...etc... AS balance
FROM invoices AS i0 LEFT JOIN invoices AS i1 ON i1.jobib=i0.jobid AND i1.id>i0.id
WHERE i1.id IS NULL
That is: “give me rows where there is no row with the same job ID but a higher invoice ID”.
If doing this between two dates, you'd need to apply the condition to both sides of the join:
SELECT i0.jobid, i0.lenses+...etc... AS balance
FROM invoices AS i0 LEFT JOIN invoices AS i1 ON
i1.jobib=i0.jobid AND i1.id>i0.id AND
i1.date BETWEEN ? AND ?
WHERE
i0.date BETWEEN ? AND ?
i1.id IS NULL
Incidentally you have an SQL-injection vulnerability from putting strings into your query. Use mysql_real_escape_string() or, better, parameterised queries to avoid these problems.
The subquery would look something like this:
SELECT * FROM INVOICES I1
WHERE DATE BETWEEN ? AND ?
AND ID = (SELECT MAX(ID) FROM INVOICES I2
WHERE DATE BETWEEN ? AND ?
AND I2.JOBID = I1.JOBID)
You should look into using parameterised queries, instead of concatenating the string with user input. At a bare minimum use mysql_real_escape_string - see here: http://www.php.net/manual/en/function.mysql-real-escape-string.php