In a Vote model, there is a validation:
validates_uniqueness_of :topic_id, :scope => [:user_id]
It is translated to the following SQL in development log:
SELECT 1 AS one FROM `votes` WHERE (`votes`.`topic_id` = BINARY 2 AND `votes`.`user_id` = 1) LIMIT 1
Where there is a BINARY in front of 2 (topic_id)? And, what does it mean?
It is an efficient way of comparing byte to byte instead of character to character
example
Suppose if your have a database table called products record which has vin_number (some column name) with record with value of vin_number say 123456
Now If you ran the this
select * from products where vin= '123456'
and
select * from products where vin = '123456 '
Both will result the same result
Notice the space in the second select
But with binary the comparison
select * from products where vin= BINARY '123456'
or
select * from producst where vin = BINARY '123456 '
A byte by byte match is done as against character to character
so the first one would result in valid result
and
the second one would no result
Here the link that will further help you on this
Related
I was running a query on my Postgresql database version 9.6.
I was selecting urls from a table image_urls having 200 urls with query:
select url from image_urls limit 10;
This query was returning the correct output with 10 urls.
However, i wanted to select image urls having http urls instead of https urls.
So, i tried to match the urls with a regex and checked the dimension of text array returned by regex matches with the help of query:
select array_length(regexp_matches(url, '^http(?!s)', 'g'), 1) from image_urls limit 10;
The above query was returning 0 results.
I was not able to understand how manipulation in selection of a column in resulting data set reduce the size of the data set ie. atleast 10 rows should have returned with whatever be the result. ?
If you have at least one match, the result of regexp_matches is array:
t=# select regexp_matches(tablename, '^pg(?!s)', 'g') from pg_tables limit 1;
regexp_matches
----------------
{pg}
(1 row)
if you have no matches - the result is not empty array, but no rows:
the function can return no rows, one row, or multiple rows (see the g
flag below)
t=# select regexp_matches(tablename, '^http(?!s)', 'g') from pg_tables;
regexp_matches
----------------
(0 rows)
and lastly array_length on no rows gives no rows:
t=# with no_rows_returned as (select ARRAY[1,2] aa from pg_tables where false)
select array_length(aa,1) from no_rows_returned;
array_length
--------------
(0 rows)
And this behaviour is not exceptional, another example with no rows without WHERE clause:
t=# select json_agg(tablename) filter (where tablename = 'no such table') from pg_tables;
json_agg
----------
(1 row)
or
t=# select unnest(array_remove(array_remove(ARRAY[1,2],1),2));
unnest
--------
(0 rows)
I have the following query where I am trying to fetch department table data based on multiple department ids using IN clause but the query that I see in the Rails server log is incorrect and hence the data fetching fails. Problem with quotes.
I tried two different options here but both of them fails because of either missing quotes or extra quotes.
OPTION 1 (ADDING QUOTES DURING CSV CONVERSION)
#depts = current_user.depts
puts #depts # prints IT Account Finance
# converting to CSV string here
#dept_ids_csv = #depts.gsub(" ", "','")
puts #dept_ids_csv # prints IT','Account','Finance
#dept_data = Department.find_by_sql(["select * from departments a where a.dept_id in (?)", #dept_ids_csv])
Expected Query Log:
select * from departments a where a.dept_id in ('IT','Account','Finance')
Actual Query Log Generated (for soem reason appends extra quotes automatically) - FAILS:
select * from departments a where a.dept_id in ('IT'',''Account'',''Finance')
OPTION 2 (REMOVING THE QUOTES DURING CSV CONVERSION)
#depts = current_user.depts
puts #depts # prints IT Account Finance
# converting to CSV string here
#dept_ids_csv = #depts.gsub(" ", ",")
puts #dept_ids_csv # prints IT,Account,Finance
#dept_data = Department.find_by_sql(["select * from departments a where a.dept_id in (?)", #dept_ids_csv])
Expected Query Log:
select * from departments a where a.dept_id in ('IT','Account','Finance')
Actual Query Log Generated (missing quotes in the IN clause) - FAILS:
select * from departments a where a.dept_id in ('IT,Account,Finance')
How do I fix this issue?
Try splitting the string into an array and passing it to a where clause.
#dept_data = Department.where(dept_id: #depts.split(" "))
How about converting string into array by .split(' ')?
Example:
#emails = ['spree#example.com', 'test#gmail.com']
User.find_by_sql(["SELECT * FROM spree_users WHERE email IN (?)", #emails])
gives
SELECT * FROM users WHERE email IN ('spree#example.com','test#gmail.com')
I am trying to achieve the following with Laravel Query builder.
I have a table called deals . Below is the basic schema
id
deal_id
merchant_id
status
deal_text
timestamps
I also have another table called merchants whose schema is
id
merchant_id
merchant_name
about
timestamps
Currently I am getting deals using the following query
$deals = DB::table('deals')
-> join ('merchants', 'deals.merchant_id', '=', 'merchants.merchant_id')
-> where ('merchant_url_text', $merchant_url_text)
-> get();
Since only 1 merchant is associated with a deal, I am getting deals and related merchant info with the query.
Now I have a 3rd table called tbl_deal_votes. Its schema looks like
id
deal_id
vote (1 if voted up, 0 if voted down)
timestamps
What I want to do is join this 3rd table (on deal_id) to my existing query and be able to also get the upvotes and down votes each deal has received.
To do this in a single query you'll probably need to use SQL subqueries, which doesn't seem to have good fluent query support in Laravel 4/5. Since you're not using Eloquent objects, the raw SQL is probably easiest to read. (Note the below example ignores your deals.deal_id and merchants.merchant_id columns, which can likely be dropped. Instead it just uses your deals.id and merchants.id fields by convention.)
$deals = DB::select(
DB::raw('
SELECT
deals.id AS deal_id,
deals.status,
deals.deal_text,
merchants.id AS merchant_id,
merchants.merchant_name,
merchants.about,
COALESCE(tbl_upvotes.upvotes_count, 0) AS upvotes_count,
COALESCE(tbl_downvotes.downvotes_count, 0) AS downvotes_count
FROM
deals
JOIN merchants ON (merchants.id = deals.merchant_id)
LEFT JOIN (
SELECT deal_id, count(*) AS upvotes_count
FROM tbl_deal_votes
WHERE vote = 1 && deal_id
GROUP BY deal_id
) tbl_upvotes ON (tbl_upvotes.deal_id = deals.id)
LEFT JOIN (
SELECT deal_id, count(*) AS downvotes_count
FROM tbl_deal_votes
WHERE vote = 0
GROUP BY deal_id
) tbl_downvotes ON (tbl_downvotes.deal_id = deals.id)
')
);
If you'd prefer to use fluent, this should work:
$upvotes_subquery = '
SELECT deal_id, count(*) AS upvotes_count
FROM tbl_deal_votes
WHERE vote = 1
GROUP BY deal_id';
$downvotes_subquery = '
SELECT deal_id, count(*) AS downvotes_count
FROM tbl_deal_votes
WHERE vote = 0
GROUP BY deal_id';
$deals = DB::table('deals')
->select([
DB::raw('deals.id AS deal_id'),
'deals.status',
'deals.deal_text',
DB::raw('merchants.id AS merchant_id'),
'merchants.merchant_name',
'merchants.about',
DB::raw('COALESCE(tbl_upvotes.upvotes_count, 0) AS upvotes_count'),
DB::raw('COALESCE(tbl_downvotes.downvotes_count, 0) AS downvotes_count')
])
->join('merchants', 'merchants.id', '=', 'deals.merchant_id')
->leftJoin(DB::raw('(' . $upvotes_subquery . ') tbl_upvotes'), function($join) {
$join->on('tbl_upvotes.deal_id', '=', 'deals.id');
})
->leftJoin(DB::raw('(' . $downvotes_subquery . ') tbl_downvotes'), function($join) {
$join->on('tbl_downvotes.deal_id', '=', 'deals.id');
})
->get();
A few notes about the fluent query:
Used the DB::raw() method to rename a few selected columns.
Otherwise, there would have been a conflict between deals.id
and merchants.id in the results.
Used COALESCE to default null votes to 0.
Split the subqueries into separate PHP strings to improve readability.
Used left joins for the subqueries so deals with no upvotes/downvotes still show up.
How to identify duplicate emails in table with . inside in ruby on rails
E.x . user 1: testaccount#gmail.com,
user 2: test.account#gmail.com,
user 3: tes.t.account#gmail.com,
user 4: test.a.ccount#gmail.com
Gmail refers to same email account for each emails included by '.' . Gmail ignores dots in email username
in postgesql:
select distinct a from (select replace(adr,'.','') as a from t) t2;
gives you unique set
select a,count(*) from (select replace(adr,'.','') as a from t) t2 group by a;
gives you how many times each value has been met
http://sqlfiddle.com/#!15/e893a2/3
To-the-dot duplicated email records can be identified directly in your SQL statement or in your ruby app code.
Here's a simple query to return all normalized email and the number of users associated with each normalized email:
User.group("replace(email,'.','')").count
which is translated to the following SQL:
SELECT COUNT(*) AS count_all, replace(email,'.','') AS replace_email FROM "users" GROUP BY replace(email,'.','')
and returns something like the following hash:
{"x#gmailcom"=>1, "da#gmailcom"=>2}
Indicating there are 2 users with normalized email equals to da#gmailcom.
Alternitevly you can use group_by in ruby code:
User.all.group_by{ |u| u.email.gsub('.','') }
How do I find a stored procedure in a Sybase database given a text string that appears somewhere in the proc? I want to see if any other proc in the db has similar logic to the one I'm looking at, and I think I have a pretty unique search string (literal)
Edit:
I'm using Sybase version 11.2
Two variations on Graeme's answer (So this also won't work on 11.2):
This lists the name of the sproc too, but will return multiple rows for each sproc if the text appears several times:
select object_name(id),* from syscomments
where texttype = 0 and text like '%whatever%'
This lists each sproc just once:
select distinct object_name(id) from syscomments
where texttype = 0 and text like '%whatever%'
In SQL Anywhere and Sybase IQ:
select * from SYS.SYSPROCEDURE where proc_defn like '%whatever%'
I'm not that familiar with ASE, but according to the docs (available from sybooks.sybase.com), it's something like:
select * from syscomments where texttype = 0 and text like '%whatever%'
Please remember, that text column in syscomments is varchar(255), so one big procedure can consist of many lines in syscomments, thus, the above selects will not find the procedure name if it has been splitted into 2 text rows in syscomments.
I suggest the following select, which will handle the above case:
declare #text varchar(100)
select #text = "%whatever%"
select distinct o.name object
from sysobjects o,
syscomments c
where o.id=c.id
and o.type='P'
and (c.text like #text
or exists(
select 1 from syscomments c2
where c.id=c2.id
and c.colid+1=c2.colid
and right(c.text,100)+ substring(c2.text, 1, 100) like #text
)
)
order by 1
-- kudos for this go to the creator of ASEisql
select * from sysobjects where
id in ( select distinct (id) from syscomments where text like '%SearchTerm%')
and xtype = 'P'
select distinct object_name(syscomments.id) 'SearchText', syscomments.id from syscomments ,sysobjects
where texttype = 0 and text like '%SearchText%' and syscomments.id=sysobjects.id and sysobjects.type='P'
Multiple rows are used to store text for database objects the value might be accross two rows. So the more accurate answer is:
select distinct object_name(sc1.id)
from syscomments sc1
left join syscomments sc2
on (sc2.id = sc1.id and
sc2.number = sc1.number and
sc2.colid2 = sc1.colid2 + ((sc1.colid + 1) / 32768) and
sc2.colid = (sc1.colid + 1) % 32768)
where
sc1.texttype = 0 and
sc2.texttype = 0 and
lower(sc1.text + sc2.text) like lower('%' || #textSearched || '%')