Update nested json array fields in Couchbase - couchbase

Please share your thought on how to update on below field
"UserList": [
{
"userAge":33,
"empID":32,
"empSal":120000,
"userDept":{
"deptId":1,
"deptEmpCount":10,
"deptNo":2
}
},
{
"userAge":33,
"empID":31,
"empSal":120000,
"userDept":{
"deptId":1,
"deptEmpCount":10,
"deptNo":2
}
}
]
want to update deptEmpCount and deptId based on empID.
I also want to remove objects based on empID.

Addition to Roi Katz answer updating more than one array field and removing from object from array.
To update array element you must use update-for syntax and last example https://docs.couchbase.com/server/current/n1ql/n1ql-language-reference/update.html
Update 2 fields you must use SET clause with each has its own FOR.
Unset you can use same way.
UPDATE default AS d
SET u.userDept.deptEmpCount = u.userDept.deptEmpCount+1 FOR u IN d.UserList WHEN u.empID = 31 END,
u.userDept.deptId = 2 FOR u IN d.UserList WHEN u.empID = 31 END
UNSET u.userDept.deptNo FOR u IN d.UserList WHEN u.empID = 31 END
WHERE ...;
To remove object from the ARRAY you can construct new array and assign it
UPDATE default AS d
SET d.UserList = ARRAY u FOR u IN d.UserList WHEN u.empID != 31 END
WHERE ...;
If you want to do complex operations on ARRAY by using subquery expression (FROM clause of subquery using expression from the parent) and able to do complete SQL on ARRAY as source of documents.
Example: Removing empID = 31 and sorting array by empID and limiting size of array to 5.
UPDATE default AS d
SET d.UserList = (SELECT u.*
FROM d.UserList AS u
WHERE u.empID != 31
ORDER BY u.empID
LIMIT 5)
WHERE ...;
To Add new object to UserList
UPDATE default AS d
SET d.UserList = ARRAY_APPEND(d.UserList, { "userAge": 34, "empID": 33, "empSal": 120000, "userDept": { "deptId": 1, "deptEmpCount": 10, "deptNo": 3 } })
WHERE ...
To Add new object to UserList if not there, if there update it.
UPDATE default d
SET d.UserList = (CASE WHEN (FIRST u FOR u IN d.UserList WHEN u.empID = 33 END) IS MISSING
THEN ARRAY_APPEND(d.UserList,
{ "userAge": 34, "empID": 33, "empSal": 120000, "userDept": { "deptId": 1, "deptEmpCount": 10, "deptNo": 3 } })
ELSE d.UserList END
END),
u.userDept.deptId = 2 FOR u IN d.UserList WHEN u.empID = 33 END
WHERE ....

First I would like to clarify, CouchDB is not Couchbase :)
UPDATE myBucket1 AS d
SET o.empSal = "120001" FOR o IN d.UserList WHEN o.empID = 32 END
Now in order to remove, you just do something similar, just use the unset keyword.
presume you have another field in the array called "dummy".
UPDATE myBucket1 AS d
UNSET o.dummy FOR o IN d.UserList WHEN o.empID = 32 END
as far as i'm aware since we are talking on array, you can't currently combine them both.
please note, that you should specify a where clause. Since you have only 1 document it doesn't really matter, but in real life- you should.
please also look at the documentation for further instructions
https://docs.couchbase.com/server/current/n1ql/n1ql-language-reference/update.html

Related

How to remove an element in jsonb integer array in PostgreSQL

On Postgres, in a table called "photo" I have a jsonb column called "id_us" containing a json integer array, simply like this one [1,2,3,4]
I would like to find the query to remove the element 3 for example.
The closer I could get is this
SELECT jsonb_set(id_us, ''
, (SELECT jsonb_agg(val)
FROM jsonb_array_elements(p.id_us) x(val)
WHERE val <> jsonb '3')
) AS id_us
FROM photo p;
Any idea how to solve this?
Thank you!
You can use a subquery containing JSONB_AGG() function while filtering out the index value 3(by starting indexing from 1) such as
WITH p AS
(
SELECT JSONB_AGG(j) AS js
FROM photo
CROSS JOIN JSONB_ARRAY_ELEMENTS(id_us)
WITH ORDINALITY arr(j,idx)
WHERE idx != 3
)
UPDATE photo
SET id_us = js
FROM p
Demo
Edit : If you need to remove the value but not index as mentioned in the comment, just use the variable j casted as numeric
WITH p AS
(
SELECT JSONB_AGG(j) AS js
FROM photo
CROSS JOIN JSONB_ARRAY_ELEMENTS(id_us)
WITH ORDINALITY arr(j,idx)
WHERE j::INT != 18
)
UPDATE photo
SET id_us = js
FROM p
Demo
P.S: using JSONB_SET(), the comma-seperated place for the removed element along with quotes will still remain in such a way that in the following
WITH p AS
(
SELECT ('{'||idx-1||'}')::TEXT[] AS idx
FROM photo
CROSS JOIN JSONB_ARRAY_ELEMENTS(id_us)
WITH ORDINALITY arr(j,idx)
WHERE j::INT = 18
)
UPDATE photo
SET id_us = JSONB_SET(id_us,idx,'""')
FROM p;
SELECT * FROM photo;
id_us
-----------------
[127, 52, "", 44]
I've run across a similar issue, and it stems from the - operator. This operator is overloaded to accept either text or integer, but acts differently for each type. Using text will remove by value, and using an integer will remove by index. But what if your value IS an integer? Well then you're shit outta luck...
If possible, you can try changing your jsonb integer array to a jsonb string array (of integers), and then the - operator should work smoothly.
e.g.
'{1,2,3}' - 2 = '{1,2}' -- removes index 2
'{1,2,3}' - '2' = '{1,2,3}' -- removes values == '2' (but '2' != 2)
'{"1","2","3"}' - 2 = '{"1","2"}' -- removes index 2
'{"1","2","3"}' - '2' = '{"1","3"}' -- removes values == '2'

MYSQL - UPDATE multiple fields based on single CASE statement

OBJECTIVE
I am looking for a way to update one or both fields using the same CASE statement
UPDATE vendor
SET special_cost =
(
CASE
WHEN
cost > 14
THEN
14
ELSE
SET special_cost = cost, cost = 14
END
)
WHERE upc = '12345678912345'
LOGIC
This is some logic that explains what I want to happen above.
if ($cost > 14) {
$special_cost = 14;
} else {
$special_cost = $cost;
$cost = 14;
}
It does not seem that there is a way to do this with a single CASE statement. Perhaps, this can be done with the mysql IF statement?
You are referring to case expressions not case statements.
You appear to want something like this:
UPDATE vendor
SET special_cost = GREATEST(cost, 14),
cost = 14
WHERE upc = '12345678912345';

How to convert non-numeric values to blank for use in case statement?

I am working on the following query:
declare #start date = '06/01/2016';
declare #end date = '07/31/2017';
----------------------------------------------------------------------------- ------------------------------------------------
-- Pull all claims with paid date in range parameter
-----------------------------------------------------------------------------
------------------------------------------------
if object_id('LA_Temp.dbo.Item19') is not null drop table LA_Temp.dbo.Item19
select distinct
c.claimid,
c.formtype,
c.facilitycode + c.billclasscode as BillType,
case when primaryclaimid = '' and resubclaimid = '' then 'Clean' else 'Other' end as CleanClaim,
-- DHHClaimtype 04 needs to be broken out based on provider specialty and location
Case when c.formtype = '1500' and cd.location = 21 and ps.specialtycode in ('05','22','1T','1F','30','1C') then '04-Hospitalist'
when c.formtype = '1500' then '04-Other'
else ' '
end as DHHClaimtype,
c.status,
c.totalpaid,
e.phystate as MemberState,
e.phycounty as MemberParish,
pc.ParishCode as MemberParishCode,
con.contracted as NetworkProvider,
reject
into LA_Temp.dbo.Item19
from claim c
inner join member m on c.memid = m.memid
inner join entity e on m.entityid = e.entid
left join LA_Temp.dbo.ParishCodes pc on e.phycounty = pc.Parish
inner join contract con on c.contractid = con.contractid
inner join provider p on c.provid = p.provid
inner join provspecialty ps on p.provid = ps.provid and ps.spectype =
'PRIMARY'
inner join claimdetail cd on c.claimid = cd.claimid and cd.claimline = 1 -- just pull the first line to
grab the location code, exclude any location codes with non-numeric values
where c.paiddate between #start and #end
and c.status in ('PAID','DENIED');
-- add the claim types to the table
EXECUTE LA_Temp.[dbo].[USP_LA_SetDHHClaimType] #Table = 'Item19';
The problem exists in the first case statement. Specifically here:
and cd.location = 21
Upon further investigation of the claimdetail (cd) table, I have found that column cd.location (datatype = int) has 4 values ('H', 'U8', 'A', 'OH') which are onviously not numeric. I would like to convert these values to blanks (if possible, not sure if blanks (' ') are compatible with int datatype) or zeros if blanks will not work. Due to the NonNumeric values, I am getting the following error (which is to be expected):
Msg 245, Level 16, State 1, Line 13
Conversion failed when converting the varchar value 'H ' to data type int.
I am aware that I can exclude these records in either the join clause or in a where statement such as:
Where cd.location not in ('H', 'U8', 'A', 'OH')
However, I want to keep the records that these values are tied to, I just want the cd.location value to be blank when it is one of these 4 values. Can someone show me how I can keep these records, by converting cd.location to ' ' when cd.location in ('H', 'U8', 'A', 'OH').
I think I got it...
Again we are focusing on the first case statement in the originally posted query:
case
-- DHHClaimtype 04 needs to be broken out based on provider specialty and location
When c.formtype = '1500' and cd.location = 21 and ps.specialtycode in ('05','22','1T','1F','30','1C')
Then '04-Hospitalist'
When c.formtype = '1500'
Then '04-Other'
else ' '
end as DHHClaimtype,
Changed to:
case
-- DHHClaimtype 04 needs to be broken out based on provider specialty and location
When c.formtype = '1500' and Case When IsNumeric(cd.location) = 0 Then ''
Else cd.location End = 21 and ps.specialtycode in ('05','22','1T','1F','30','1C') then '04-Hospitalist'
When c.formtype = '1500'
Then '04-Other'
else ' '
end as DHHClaimtype,

MySQL IF returning nothing

I am trying to do some optimisation, currently post mysql work is done on the results to set a new paramter $class_subject... so i am trying get this already calculated in mysql...
SELECT
class_grade.results as results,
subjects.subject as subject,
subjects_pseudonyms.pseudonym as pseudonym,
IF( subjects_pseudonyms.pseudonym = null, subjects.subject, subjects_pseudonyms.pseudonym ) as class_subject
FROM
class_grade
INNER JOIN class ON class_grade.class_ID = class.class_ID
INNER JOIN subjects ON class.subject_ID = subjects.a_ID
LEFT JOIN subjects_pseudonyms ON class.subject_pseudonym_ID = subjects_pseudonyms.a_ID
WHERE
class_grade.teacher_ID = :teacher_id AND
class_grade.class_ID = :current_class_ID AND
class_grade.report_set_ID = :report_set_ID AND
class_grade.student_ID = :current_student_ID
In the above query the pseudonym might be null, if so I am attempting to set a new variable class_subject to be either subject or pseudonym...
The query runs fine, a results example is:
[results] => 71
[subject] => Law
[pseudonym] =>
[class_subject] =>
The problem is, the class_subject is not being populated..
Is there something wrong with my IF() cond?
Thanks,
John
You need to use IS NULL instead of = NULL or ISNULL()
http://dev.mysql.com/doc/refman/5.0/en/comparison-operators.html#function_isnull
ISNULL() can be used instead of = to test whether a value is NULL.
(Comparing a value to NULL using = always yields false.)

SQL Server 2008: Error converting data type nvarchar to float

Presently troubleshooting a problem where running this SQL query:
UPDATE tblBenchmarkData
SET OriginalValue = DataValue, OriginalUnitID = DataUnitID,
DataValue = CAST(DataValue AS float) * 1.335
WHERE
FieldDataSetID = '6956beeb-a1e7-47f2-96db-0044746ad6d5'
AND ZEGCodeID IN
(SELECT ZEGCodeID FROM tblZEGCode
WHERE(ZEGCode = 'C004') OR
(LEFT(ZEGParentCode, 4) = 'C004'))
Results in the following error:
Msg 8114, Level 16, State 5, Line 1
Error converting data type nvarchar to float.
The really odd thing is, if I change the UPDATE to SELECT to inspect the values that are retrieved are numerical values:
SELECT DataValue
FROM tblBenchmarkData
WHERE FieldDataSetID = '6956beeb-a1e7-47f2-96db-0044746ad6d5'
AND ZEGCodeID IN
(SELECT ZEGCodeID
FROM tblZEGCode WHERE(ZEGCode = 'C004') OR
(LEFT(ZEGParentCode, 4) = 'C004'))
Here are the results:
DataValue
2285260
1205310
Would like to use TRY_PARSE or something like that; however, we are running on SQL Server 2008 rather than SQL Server 2012. Does anyone have any suggestions? TIA.
It would be helpful to see the schema definition of tblBenchmarkData, but you could try using ISNUMERIC in your query. Something like:
SET DataValue = CASE WHEN ISNUMERIC(DataValue)=1 THEN CAST(DataValue AS float) * 1.335
ELSE 0 END
Order of execution not always matches one's expectations.
If you set a where clause, it generally does not mean the calculations in the select list will only be applied to the rows that match that where. SQL Server may easily decide to do a bulk calculation and then filter out unwanted rows.
That said, you can easily write try_parse yourself:
create function dbo.try_parse(#v nvarchar(30))
returns float
with schemabinding, returns null on null input
as
begin
if isnumeric(#v) = 1
return cast(#v as float);
return null;
end;
So starting with your update query that's giving an error (please forgive me for rewriting it for my own clarity):
UPDATE B
SET
OriginalValue = DataValue,
OriginalUnitID = DataUnitID,
DataValue = CAST(DataValue AS float) * 1.335
FROM
dbo.tblBenchmarkData B
INNER JOIN dbo.tblZEGCode Z
ON B.ZEGCodeID = Z.ZEGCodeID
WHERE
B.FieldDataSetID = '6956beeb-a1e7-47f2-96db-0044746ad6d5'
AND (
Z.ZEGCode = 'C004' OR
Z.ZEGParentCode LIKE 'C004%'
)
I think you'll find that a SELECT statement with exactly the same expressions will give the same error:
SELECT
OriginalValue,
DataValue NewOriginalValue,
OriginalUnitID,
DataUnitID OriginalUnitID,
DataValue,
CAST(DataValue AS float) * 1.335 NewDataValue
FROM
dbo.tblBenchmarkData B
INNER JOIN dbo.tblZEGCode Z
ON B.ZEGCodeID = Z.ZEGCodeID
WHERE
B.FieldDataSetID = '6956beeb-a1e7-47f2-96db-0044746ad6d5'
AND (
Z.ZEGCode = 'C004' OR
Z.ZEGParentCode LIKE 'C004%'
)
This should show you the rows that can't convert:
SELECT
B.*
FROM
dbo.tblBenchmarkData B
INNER JOIN dbo.tblZEGCode Z
ON B.ZEGCodeID = Z.ZEGCodeID
WHERE
B.FieldDataSetID = '6956beeb-a1e7-47f2-96db-0044746ad6d5'
AND (
Z.ZEGCode = 'C004' OR
Z.ZEGParentCode LIKE 'C004%'
)
AND IsNumeric(DataValue) = 0
-- AND IsNumeric(DataValue + 'E0') = 0 -- try this if the prior doesn't work
The trick in the last commented line is to tack on things to the string to force only valid numbers to be numeric. For example, if you wanted only integers, IsNumeric(DataValue + '.0E0') = 0 would show you those that aren't.