Multiple aggregate queries using the sequel gem - ruby

Is it possible to use sequel to execute a query like this:
select (select count(*) from users where blah = 'blah') as "users",
(select count(*) from contacts where blah = 'blah') as "contacts"
I know I can execute these queries one a time using sequel, but I would like to execute them all at the same time.

You can do that query without writing raw SQL with the following:
dataset = DB.select {[
DB[:users].where(blah: 'blah').select { count('*') }.as(:users),
DB[:contacts].where(blah: 'blah').select { count('*') }.as(:contacts)
]}
dataset.first
# => { users: X, contacts: Y }
dataset.sql
# => "SELECT (SELECT count('*') FROM \"users\" WHERE (\"blah\" = 'blah')) AS \"users\",
# (SELECT count('*') FROM \"contacts\" WHERE (\"blah\" = 'blah')) AS \"contacts\""

Yes you can do it ok with the sequel gem.
require 'sequel'
DB = Sequel.sqlite # memory database
DB.create_table :users do
primary_key :id
String :name
end
users = DB[:users] # Create a dataset
users.insert(:name => 'jim')
DB.create_table :contacts do
primary_key :id
String :name
end
contacts = DB[:contacts] # Create a dataset
contacts.insert(:name => 'first')
DB['select (select count(*) from users where name = "jim") as users,
(select count(*) from contacts where name = "first") as contacts'].each do |row|
puts row
end
#{:users=>1, :contacts=>1}
It should be noted however that it is not a great idea to include raw strings in a sequel method.
They can be extracted as follows:
DB['select (select count(*) from users where name = ?) as users,
(select count(*) from contacts where name = ?) as contacts, 'jim', 'first'].each do |row|
puts row
end
Also as noted in another answer you could express this query completely without resorting to SQL which is more in the spirit of the module. :
dataset = DB.select {[
DB[:users].where(name: 'jim').select { count('*') }.as(:users),
DB[:contacts].where(name: 'first').select { count('*') }.as(:contacts)
]}
dataset.sql
# SELECT (SELECT count('*') FROM `users` WHERE (`name` = 'jim')) AS 'users', (SELECT count('*') FROM `contacts` WHERE (`name` = 'first')) AS 'contacts'
dataset.first
# {:users=>1, :contacts=>1}

You can execute as you mentioned above, there is no issue with your query .
I have executed the same and it was executed without any issues ..
below was what i have executed
select( SELECT count(*) FROM `abcde` where `User_ID`=4001) as "aa",
(SELECT count(*) FROM `abcdef` where `User_ID`=4018) as "bbb"
results :
aa bbb
181 364

you need to add * from after select and may be some parenthesis:
select * from ((select count(*) from users where blah = 'blah') as "users",
(select count(*) from contacts where blah = 'blah') as "contacts")

Related

how to write a Oracle view with this query?

I am using oracle 11g. I want to query with 3 queries.
First one, it is the main. Select to find condition.
Select role, name from tablerole where name is not null and ID=#param1;
This query will return #role with 2 level (admin and user)
The 2 other sub queries will base on this condition.
Up on the first query.
If role='admin' then select*from tablescreen where name is not null and ID=#param1;
If role='user' then select*from tablescreen where name='2';
#param1 is given when I call this view or when I using.
I consider it will be view or function or procedure best for this query.
How to write this query that can accept an input parameter into the query for looping source and return output where matched condition.
Thanks for your kindness.
Nam hmoob.
As far as I understood the question, that would be a view that consists of two select statements:
one that uses condition for admin
another one for user
The first query you posted will be used in a join with the tablescreen table. Something like this:
create or replace view v_role as
-- select for ADMIN
select r.id, s.whatever
from tablescreen s join tablerole r on r.id = s.id
where s.name is not null
and r.role = 'admin'
union all
-- select for USER
select r.id, s.whatever
from tablescreen s join tablerole r on r.id = s.id
where s.name = '2'
and r.name = 'user';
Or, as Zynon suggested, without union:
select r.id, s.whatever
from tablescreen s join tablerole r on r.id = s.id
where ( s.name is not null
and r.role = 'admin'
)
or ( s.name = '2'
and r.name = 'user'
);
You'd then use it as
select * from v_role v where v.id = &param1;

Syntax to escape a reserved word in Oracle while using abbreviated table names

I have an Oracle 11g database with table named "time_recs". I need to run a query in SQL Developer, including a column named comment.
As comment is a reserved word, I need to escape it, that´s ok. The problem is I can´t find the correct syntax when you are using abbreviated table names.
E.g.: If I run select "comments" from "time_recs"; it works well.
But the report I need to run is pasted below. If you see line 17 ("tr"."comment"), I´ve tried a lot of different things: quotes, double quotes, etc. Still I can´t make it work as I keep getting the "invalid identifier" error
Any help will be really appreciated.
select
tr.record_date as "Date"
, ua4.string_value as "Employee Number"
, case when p.id_parent = 'root' then p.pname else pp.pname end as "Parent Project Name"
, p.pname as "Project"
, ct.pname as "Work Package"
, tra1.string_value as "Cost Center"
, ua1.string_value as "Discipline"
, case when ua3.string_value = 'Research' then 'R' else 'D' end as "R or D"
, 'N/A' as "Sub Discipline"
, tra2.string_value as "Primary Indication"
, tra3.string_value as "Project Phase"
, pa1.string_value as "Project Template Type"
, pa2.string_value as "Secondary Indication"
, pa3.string_value as "Therapeutic Area"
, sum(tr.time_amount) as "Hours"
, "tr"."comment"
from time_recs tr
left join users us on
tr.id_user = us.id_user
left join users_attribs ua1 on
tr.id_user = ua1.id_user
left join projects p on
tr.id_project = p.id_project
join projects pp on
pp.id_project = p.id_parent
join codes_tasks ct on
ct.id_code = tr.id_code_task
left join time_recs_attribs tra1 on
tr.id_time_rec = tra1.id_time_rec
join attribute_types attr1 on
attr1.id_attr_type = tra1.id_attr_type and attr1.pname = 'Cost Center'
join attribute_types atua2 on
atua2.id_attr_type = ua1.id_attr_type and atua2.pname = 'Discipline'
left join users_attribs ua3 on
tr.id_user = ua3.id_user
join attribute_types atua3 on
atua3.id_attr_type = ua3.id_attr_type and atua3.pname = 'Organization'
left join users_attribs ua4 on
tr.id_user = ua4.id_user and ua4.id_attr_type='D00C686107154F3FB2B97F47B172CB7F' --Employe Number
left join time_recs_attribs tra2 on
tr.id_time_rec = tra2.id_time_rec
join attribute_types attr2 on
attr2.id_attr_type = tra2.id_attr_type and attr2.pname = 'Primary Indication'
left join time_recs_attribs tra3 on
tr.ID_TIME_REC = tra3.ID_TIME_REC
join attribute_types attr3 on
attr3.id_attr_type = tra3.id_attr_type and attr3.pname = 'Project Phase'
right join projects_attribs pa1 on
tr.id_project = pa1.id_project
join attribute_types atpa1 on
atpa1.id_attr_type = pa1.id_attr_type and atpa1.pname = 'Project Template Type'
left join projects_attribs pa2 on
tr.id_project = pa2.id_project
join attribute_types atpa2 on
atpa2.id_attr_type = pa2.id_attr_type and atpa2.pname = 'Secondary Indication'
left join projects_attribs pa3 on
tr.id_project = pa3.id_project
join attribute_types atpa3 on
atpa3.id_attr_type = pa3.id_attr_type and atpa3.pname = 'Therapeutic Area'
where
tr.record_date >= 20190101
and tr.record_date <= 20190131
having sum(tr.time_amount) >0
group by
tr.record_date
, ua4.string_value
, case when p.id_parent = 'root' then p.pname else pp.pname end
, p.pname
, ct.pname
, tra1.string_value
, ua1.string_value
, case when ua3.string_value = 'Research' then 'R' else 'D' end
, 'N/A'
, tra2.string_value
, tra3.string_value
, pa1.string_value
, pa2.string_value
, pa3.string_value
;
You don't need anything; use alias as is:
SQL> create table time_recs ("comment" varchar2(10));
Table created.
SQL> insert into time_recs ("comment") values ('Littlefoot');
1 row created.
SQL> select tr."comment" --> here
2 from time_recs tr;
comment
----------
Littlefoot
SQL>
thank you for your comments. Well, now I see that I have to be more careful with typing. The column is named comment (lowercase without quotes).
It works if I run the following simple query:
select "comment" from "time_recs";
However, I can´t make it work with the abbreviated table names. – I´m also providing a list of the table fields screenshot of table fields

Using IF statements in Oracle when trying to return data

How do I return data out of IF statements? I have a IF statement which is meant to return a different result dependent of the result of that statement.
IF :Value = 1 THEN
SELECT Name FROM TABLE_A
ELSEIF :Value = 2 THEN
SELECT Name FROM TABLE_B
ELSEIF :Value = 3 THEN
SELECT Name FROM TABLE_C
but this doesn't work. It expects an INTO statement in those selects. I suspect this is because Oracle can't return out of a block?
Is there a quicker way to return those select statements without creating table variables to store the data or messing around with functions?
You can do this by plain SQL:
SELECT
':Value' user_input,
CASE
WHEN ':Value' IN('a1','a2','a3')
THEN (select name from table_a)
WHEN ':Value' = 'i'
THEN (select name from table_b)
END AS output
FROM
dual
(good info about case)
If you want more than one result in your cases, then you may opt to an intelligent UNION:
SELECT t1_Col_1, t1_Col_2,'&VALUE' from TABLE_1
WHERE '&VALUE' = '1'
UNION ALL
SELECT t2_Col_1, t2_Col_2,'&VALUE' from TABLE_2
WHERE '&VALUE' = '2'
In this solution, types and number of tx_Coln must be the same.

How do I get the results of a group_and_count using the Sequel gem?

I have a Sequel-based class that I need to do some summaries on.
I'm doing a group_and_count, and I can see that it's generating the right query. However, when I try to access the results, Sequel is trying to coerce the rows into the class I'm accessing through:
[33] pry(main)> grouped = Pancakes::Stack.active.group_and_count('health_state')
=> #<Sequel::Mysql2::Dataset: "SELECT 'health_state', count(*) AS `count` FROM `pancakes_stacks` WHERE (`deleted_at` IS NULL) GROUP BY 'health_state'">
[34] pry(main)> grouped.each_entry { |row| puts row }
I sequel: (0.001344s) SELECT 'health_state', count(*) AS `count` FROM `pancakes_stacks` WHERE (`deleted_at` IS NULL) GROUP BY 'health_state'
#<Pancakes::Stack:0x000000089251a0>
=> #<Sequel::Mysql2::Dataset: "SELECT 'health_state', count(*) AS `count` FROM `pancakes_stacks` WHERE (`deleted_at` IS NULL) GROUP BY 'health_state'">
[35] pry(main)> grouped.first
I sequel: (0.001502s) SELECT 'health_state', count(*) AS `count` FROM `pancakes_stacks` WHERE (`deleted_at` IS NULL) GROUP BY 'health_state' LIMIT 1
I sequel: (0.001243s) SELECT * FROM `pancakes_stacks` WHERE (`id` IS NULL) LIMIT 1
=> #<Pancakes::Stack:0x44b068c>
I can get what I need by working around the ORM stuff, but that appears to require me to re-implement the active method above, and figure out how to get the table name from the class name:
[38] pry(main)> groupie = grouped.db[:pancakes_stacks].where(deleted_at:nil).group_and_count(:health_state)
=> #<Sequel::Mysql2::Dataset: "SELECT `health_state`, count(*) AS `count` FROM `pancakes_stacks` WHERE (`deleted_at` IS NULL) GROUP BY `health_state`">
[39] pry(main)> groupie.each_entry { |row| puts row }
I sequel: (0.001598s) SELECT `health_state`, count(*) AS `count` FROM `pancakes_stacks` WHERE (`deleted_at` IS NULL) GROUP BY `health_state`
{:health_state=>nil, :count=>3}
{:health_state=>"healthy", :count=>10}
Isn't there an easier way? I've spent a lot of time on the querying page, but none of the examples show how to access the results.
You probably just want to add a .naked to your dataset, which will make the dataset return hashes instead of model objects.
I personally use the square brackets method to get the :count attribute for a row:
row[:count]

How to write Order by expression in JPQL

PostgreSQL and MySQL offers to write expression into ORDER BY clause in SQL query. It allows to sort items by some column but the special values are on the top. The SQL looks like this one. ( works in Postgres )
select * from article order by id = 4, id desc;
Now I want to write it in the JPQL but it doesn't work. My attempt is:
#NamedQuery(name = "Article.special", query = "SELECT a FROM Article a ORDER BY ( a.id = :id ) DESC, a.id DESC")
This is JPA 1.0 with Hibernate driver. Application server throws this exception on deploy.
ERROR [SessionFactoryImpl] Error in named query: Article.special
org.hibernate.hql.ast.QuerySyntaxException: unexpected AST node: = near line 1, column 73 [SELECT a FROM cz.cvut.fel.sk.model.department.Article a ORDER BY ( a.id = :id ) DESC, a.id DESC]
at org.hibernate.hql.ast.QuerySyntaxException.convert(QuerySyntaxException.java:54)
Thanks a lot.
For a named query, (ORDER BY ( a.id = :id ) or ORDER BY (:id )) won't work as DSC/ASC can't be parametrized at run-time.
1) Dynamic way if ordering element varies at runtime.
String query = "SELECT a FROM Article a ORDER BY "+orderElement+" DESC, a.id DESC";
entityManager.createQuery(query).getResultList();
2) Static way in entity bean if ordering element is fixed.
Field level:
#OrderBy("id ASC")
List<Article> articles;
Method level:
#OrderBy("id DESC")
public List<Article> getArticles() {...};

Resources