How to query jsonb? - phoenix-framework

I am storing settings into a config field as:
schema "teams" do
field :owner_id, :integer
field :is_base_team, :boolean
field :config, :map
has_many :team_users, {"team_user", App.TeamUser}
end
So, I need to build query that reads parameter see_owner within config as:
teams_users =
from(t in Team, where: t.owner_id == ^user_id and fragment("?->>'see_owner' == ?", t.config, true))
|> Repo.all()
|> Repo.preload(:team_users)
However, I got error:
** (Postgrex.Error) ERROR (undefined_function): operator does not exist: text == boolean
(ecto) lib/ecto/adapters/sql.ex:395: Ecto.Adapters.SQL.execute_and_cache/7
(ecto) lib/ecto/repo/queryable.ex:127: Ecto.Repo.Queryable.execute/5
(ecto) lib/ecto/repo/queryable.ex:40: Ecto.Repo.Queryable.all/4
(app) web/channels/user_socket.ex:67: App.UserSocket.get_team_users_ids/1
(app) web/channels/user_socket.ex:40: App.UserSocket.connect/2
(phoenix) lib/phoenix/socket/transport.ex:167: Phoenix.Socket.Transport.connect_vsn/6
(phoenix) lib/phoenix/transports/websocket.ex:73: Phoenix.Transports.WebSocket.init/2
(phoenix) lib/phoenix/endpoint/cowboy_websocket.ex:12: Phoenix.Endpoint.CowboyWebSocket.init/3
(cowboy) src/cowboy_handler.erl:64: :cowboy_handler.handler_init/4
(cowboy) src/cowboy_protocol.erl:442: :cowboy_protocol.execute/4
So, how would I add to my query a checking of config.see_owner where config is a jsonb where see_owner is a boolean property ?
I am using ecto 2.0.0-rc.5
EDIT
I have fixed the postgres query as:
from(t in Team, where: t.owner_id == ^user_id and fragment("?->> 'see_owner' = '?'", t.config, true))
in the log I, it was translated as:
SELECT t0."id", t0."owner_id", t0."is_base_team", t0."config" FROM "teams" AS t0 WHERE ((t0."owner_id" = $1) AND t0."config"->> 'see_owner' = 'TRUE') [3]
but the result is empty, however, there are teams with config equals to {"see_owner": true}
EDIT2
Checking with owner_id, I got error:
sql> SELECT t0."id", t0."owner_id", t0."is_base_team", t0."config" FROM "teams" AS t0 WHERE ((t0."owner_id" = $1) AND t0."config"->> 'see_owner' = 'TRUE') [3]
[2016-06-01 17:43:33] [42804] ERROR: cannot subscript type boolean because it is not an array
I removed the owner_id check, but I got empty result:
SELECT t0."id", t0."owner_id", t0."is_base_team", t0."config" FROM "teams" AS t0 WHERE (t0."config"->> 'see_owner' = 'TRUE')
[2016-06-01 17:44:09] 0 rows retrieved in 9ms (execution: 4ms, fetching: 5ms)
I removed the owner_id check, and I used small letters for 'see_owner' = 'TRUE' as 'see_owner' = 'true', I got the results without errors:
sql> SELECT t0."id", t0."owner_id", t0."is_base_team", t0."config" FROM "teams" AS t0 WHERE (t0."config"->> 'see_owner' = 'true')
[2016-06-01 17:46:40] 16 rows retrieved starting from 1 in 7ms (execution: 3ms, fetching: 4ms)
so, I think that Ecto needs to translate boolean type to postrgres native query without converting it to capital letters like TRUE or FALSE as it currently does.
also, I don't know why native query with owner_id got error, as I copied the resulted native query from logs, and it should be working correctly..

The problem here is your conditional, == is not valid in PostgreSQL.
Try this:
from(t in Team, where: t.owner_id == ^user_id and fragment("?->>'see_owner' = ?", t.config, true))

Related

SQLRPGLE & JSON_OBJECT CTE Statements -101 Error

This program compiles correctly, we are on V7R3 - but when running it receives an SQLCOD of -101 and an SQLSTATE code is 54011 which states: Too many columns were specified for a table, view, or table function. This is a very small JSON that is being created so I do not think that is the issue.
The RPGLE code:
dcl-s OutFile sqltype(dbclob_file);
xfil_tofile = '/ServiceID-REFCODJ.json';
Clear OutFile;
OutFile_Name = %TrimR(XFil_ToFile);
OutFile_NL = %Len(%TrimR(OutFile_Name));
OutFile_FO = IFSFileCreate;
OutFile_FO = IFSFileOverWrite;
exec sql
With elm (erpRef) as (select json_object
('ServiceID' VALUE trim(s.ServiceID),
'ERPReferenceID' VALUE trim(i.RefCod) )
FROM PADIMH I
INNER JOIN PADGUIDS G ON G.REFCOD = I.REFCOD
INNER JOIN PADSERV S ON S.GUID = G.GUID
WHERE G.XMLTYPE = 'Service')
, arr (arrDta) as (values json_array (
select erpRef from elm format json))
, erpReferences (refs) as ( select json_object ('erpReferences' :
arrDta Format json) from arr)
, headerData (hdrData) as (select json_object(
'InstanceName' : trim(Cntry) )
from padxmlhdr
where cntry = 'US')
VALUES (
select json_object('header' : hdrData format json,
'erpReferenceData' value refs format json)
from headerData, erpReferences )
INTO :OutFile;
Any help with this would be very much appreciated, this is our first attempt at creating JSON for sending and have not experienced this issue before.
Thanks,
John
I am sorry for the delay in getting back to this issue. It has been corrected, the issue was with the "values" statement.
This is the correct code needed to make it work correctly:
Select json_object('header' : hdrData format json,
'erpReferenceData' value refs format json)
INTO :OutFile
From headerData, erpReferences )

Oracle decode logic implementation using Slick

I have following problem - there is sql with DECODE oracle function:
SELECT u.URLTYPE, u.URL
FROM KAA.ENTITYURLS u
JOIN KAA.ENTITY e
ON decode(e.isurlconfigured, 0, e.urlparentcode, 1, e.CODE,
NULL)=u.ENTITYCODE
JOIN CASINO.Casinos c ON e.casinocode = c.code
WHERE e.NAME = $entityName
AND C.NAME = $casinoName
I'm trying to realize this sql in my slick code , like:
val queryUrlsEntityName = for {
entityUrl <- entityUrls
entity <- entities.filter(e => e.name.trim===entityName &&
entityUrl.entityCode.asColumnOf[Option[Int]]==(e.isURLConfigured match
{
case Some(0) => e.urlParentCode
case Some(1) => e.code.asColumnOf[Option[Int]]
case _ => None
}
)
)
casino <- casinos.filter(_.name.trim===casinoName) if
entity.casinoCode==casino.code
} yield (entityUrl)
But I don't understand how can I implement of matching of values in line
case Some(0) => e.urlParentCode
because I'm getting error
constructor cannot be instantiated to expected type;
[error] found : Some[A]
[error] required: slick.lifted.Rep[Option[Int]]
[error] case Some(0) => e.urlParentCode
Thanks for any advice
You should rewrite your code in pattern-matching section so you could compare required Rep[Option[Int]] - to left type, in your case it's Option[Int], or transform Rep[Option[Int]] to Option[Int] type. Rep is only the replacement to the column datatype in slick. I would prefer the first variant - this answer shows how to make the transformation from Rep, or you can use map directly:
map(u => (u.someField)).result.map(_.headOption.match {
case Some(0) => .....
})

Oracle/PLSQL performance tips

I living problem in my query. When i add ROUND and DECODE query takes too long time but when i delete directly return value. When i search for sql advice no any advice. How i can fix this 2 syntax ?
SELECT I.*,
Q.INVOICE_DATE,
Q.SERIES_ID IFS_SERIES_ID,
Q.INVOICE_NO,
Q.IDENTITY,
Q.IDENTITY_NAME,
Q.ASSOCIATION_NO,
Q.NET_CURR_AMOUNT,
Q.VAT_CURR_AMOUNT,
Q.TOTAL_CURR_AMOUNT,
Q.CURRENCY_CODE,
ROUND(Q.CURR_RATE,:"SYS_B_0") CURR_RATE,
Q.PROFILE_ID DEFAULT_PROFILE_ID,
X.XML_CONTENT,
DECODE(NVL(DBMS_LOB.INSTR(X.XML_CONTENT,:"SYS_B_1",:"SYS_B_2",:"SYS_B_3"), :"SYS_B_4"), :"SYS_B_5",:"SYS_B_6", :"SYS_B_7") SINGED_UBL,
X.SCHEMATRON_RESULT,
q.SHIPMENT_ID,
APP.TBN_UTILITY_API.GET_NUMBER(I.COMPANY, I.INVOICE_ID) DESPATCH_REFERENCE,
X.OBJID XML_OBJID,
X.OBJVERSION XML_OBJVERSION,
APP.API_MODULE.GET_DESC(I.MODULE_ID) MODULE_NAME
FROM APP.TREF_INVOICE I,
APP.TREF_INVOICE_INFO_QRY Q,
APP.TREF_XML_ARCHIVE X
WHERE Q.COMPANY = I.COMPANY
AND Q.INVOICE_ID = I.INVOICE_ID
AND X.XML_ARCHIVE_ID(+) = I.XML_ARCHIVE_ID
AND I.COMPANY = :COMPANY
AND I.INVOICE_ID = :INVOICE_ID
You should trace one or more executions of each statement to see exactly what it does. When you profile the trace data you will know what to do.
SQL> select value from v$diag_info where name = 'Default Trace File'/* name of the trace file */;
SQL> exec dbms_monitor.session_trace_enable(null, null, true, false, 'all_executions')
SQL> your query executed under normal circumstances
SQL> exec dbms_monitor.session_trace_disable(null, null)

Query Builder reading conditional like a column - Unknown column in field list

I have a MySQL expression that uses a conditional IF statement. As a MySQL expression, it returns TRUE or FALSE, but when I use it in CodeIgniter's query builder, I get an error. The error suggests that the outcome of the conditional is reading like a column, but how can I fix this? Thanks.
MySQL:
SELECT
positions.max_vol AS attendee_limit,
COUNT(users_positions.user_id) AS total_attendees,
IF(COUNT(users_positions.user_id) < positions.max_vol
OR positions.max_vol IS NULL,
TRUE,
FALSE) AS result
FROM
positions
INNER JOIN
users_positions ON positions.id = users_positions.position_id
WHERE
positions.id = 16
AND users_positions.calendar_date = '2016-09-05'
Function:
private function check_attendee_limit($pos_id = NULL, $date = NULL)
{
$this->db->select('positions.max_vol, COUNT(users_positions.user_id), IF(COUNT(users_positions.user_id) < positions.max_vol OR positions.max_vol IS NULL, TRUE, FALSE)');
$this->db->from('positions');
$this->db->join('users_positions', "positions.id = users_positions.position_id", 'inner');
$this->db->where('positions.id', $pos_id);
$this->db->where('users_positions.calendar_date', $date);
$query = $this->db->get();
return $query->result(); // return the rows selected
}
Error:
A Database Error Occurred
Error Number: 1054
Unknown column 'TRUE' in 'field list'
SELECT `positions`.`max_vol`, COUNT(users_positions.user_id), IF(COUNT(users_positions.user_id) < positions.max_vol OR positions.max_vol IS NULL, `TRUE`, FALSE)
FROM `positions`
INNER JOIN `users_positions` ON `positions`.`id` = `users_positions`.`position_id`
WHERE `positions`.`id` = '15'
AND `users_positions`.`calendar_date` = '2016-09-05'
Filename: models/projects/Calendar_model.php
Line Number: 141
CI adds backticks - which means you've to prevent CI from escaping your select
Try this instead
$this->db->select('positions.max_vol, COUNT(users_positions.user_id), IF(COUNT(users_positions.user_id) < positions.max_vol OR positions.max_vol IS NULL, TRUE, FALSE)', false);
If you are worry about security - in your case it doesn't matter because you don't use any user input in your select query.
You can find more informations about the Query Builder here

CT_FETCH error in PowerBuilder Program

I'm still learning PowerBuilder and trying to get familiar with it. I'm receiving the following error when I try to run a program against a specific document in my database:
ct_fetch(): user api layer: internal common library error: The bind of result set item 4 resulted in an overflow. ErrCode: 2.
What does this error mean? What is item 4? This is only when I run this program against a specific document in my database, any other document works fine. Please see code below:
string s_doc_nmbr, s_doc_type, s_pvds_doc_status, s_sql
long l_rtn, l_current_fl, l_apld_fl, l_obj_id
integer l_pvds_obj_id, i_count
IF cbx_1.checked = True THEN
SELECT dsk_obj.obj_usr_num,
dsk_obj.obj_type,
preaward_validation_doc_status.doc_status,
preaward_validation_doc_status.obj_id
INTO :s_doc_nmbr, :s_doc_type, :s_pvds_doc_status, :l_pvds_obj_id
FROM dbo.dsk_obj dsk_obj,
preaward_validation_doc_status
WHERE dsk_obj.obj_id = :gx_l_doc_obj_id
AND preaward_validation_doc_status.obj_id = dsk_obj.obj_id
using SQLCA;
l_rtn = sqlca.uf_sqlerrcheck("w_pdutl095_main", "ue_run_script", TRUE)
IF l_rtn = -1 THEN
RETURN -1
END IF
//check to see if document (via obj_id) exists in the preaward_validation_doc_status table.
SELECT count(*)
into :i_count
FROM preaward_validation_doc_status
where obj_id = :l_pvds_obj_id
USING SQLCA;
IF i_count = 0 THEN
//document doesn't exist
// messagebox("Update Preaward Validation Doc Status", + gx_s_doc_nmbr + ' does not exist in the Preaward Validation Document Status table.', Stopsign!)
//MC - 070815-0030-MC Updating code to insert row into preaward_validation_doc_status if row doesn't already exist
// s_sql = "insert into preaward_validation_doc_status(obj_id, doc_status) values (:gx_l_doc_obj_id, 'SUCCESS') "
INSERT INTO preaward_validation_doc_status(obj_id, doc_status)
VALUES (:gx_l_doc_obj_id, 'SUCCESS')
USING SQLCA;
IF sqlca.sqldbcode <> 0 then
messagebox('SQL ERROR Message',string(sqlca.sqldbcode)+'-'+sqlca.sqlerrtext)
return -1
end if
MessageBox("PreAward Validation ", 'Document number ' + gx_s_doc_nmbr + ' has been inserted and marked as SUCCESS for PreAward Validation.')
return 1
Else
//Update document status in the preaward_validation_doc_status table to SUCCESS
Update preaward_validation_doc_status
Set doc_status = 'SUCCESS'
where obj_id = :l_pvds_obj_id
USING SQLCA;
IF sqlca.sqldbcode <> 0 then
messagebox('SQL ERROR Message',string(sqlca.sqldbcode)+'-'+sqlca.sqlerrtext)
return -1
end if
MessageBox("PreAward Validation ", 'Document number '+ gx_s_doc_nmbr + ' has been marked as SUCCESS for PreAward Validation.')
End IF
update crt_script
set alt_1 = 'Acknowledged' where
ticket_nmbr = :gx_s_ticket_nmbr and
alt_2 = 'Running' and
doc_nmbr = :gx_s_doc_nmbr
USING SQLCA;
Return 1
ElseIF cbx_1.checked = False THEN
messagebox("Update Preaward Validation Doc Status", 'The acknowledgment checkbox must be selected for the script to run successfully. The script will now exit. Please relaunch the script and try again . ', Stopsign!)
Return -1
End IF
Save yourself a ton of headaches and use datawindows... You'd reduce that entire script to about 10 lines of code.
Paul Horan gave you good advice. This would be simple using DataWindows or DataStores. Terry Voth is on the right track for your problem.
In your code, Variable l_pvds_obj_id needs to be the same type as gx_l_doc_obj_id because if you get a result, it will always be equal to it. From the apparent naming scheme it was intended to be long. This is the kind of stuff we look for in peer reviews.
A few other things:
Most of the time you want SQLCode not SQLDbCode but you didn't say what database you're using.
After you UPDATE crt_script you need to check the result.
I don't see COMMIT or ROLLBACK. Autocommit isn't suitable when you need to update multiple tables.
You aren't using most of the values from the first SELECT. Perhaps you've simplified your code for posting or troubleshooting.

Resources