go to post Vitaliy Serdtsev · Aug 5, 2020 Entity–attribute–value model is usually used for this purpose. I have already written about this at the time: SQL index for array property elements.
go to post Vitaliy Serdtsev · Jul 9, 2020 select *, case when a is JSON then 1 else 0 end aa, case when b is JSON then 1 else 0 end bb, case when c is JSON then 1 else 0 end cc from (SELECT 1 a, JSON_OBJECT('id':1) b, '{"id":1}' c)
go to post Vitaliy Serdtsev · Jun 10, 2020 Here is a ready-made example (works even in last Caché): Class dc.test Extends %Persistent { Property title As %VarString; Property author As %VarString; /// do ##class(dc.test).test() ClassMethod test() { &sql(truncate table dc.test) &sql(insert into dc.test(title,author) select 'For Whom the Bell Tolls','Hemmingway' union select 'The Invisible Man','Ellison' union select 'Tender is the Night','Fitzgerald') set provider=##class(%ZEN.Auxiliary.altJSONSQLProvider).%New(), provider.sql="select title,author from dc.test", provider.arrayName="items", provider.maxRows = 0, provider.%Format = "tw" do provider.%WriteJSONStreamFromSQL(.stream,,,,,provider) set json={}.%FromJSON(stream), json.results=json.items.%Size() write json.%ToJSON() } }Result: USER>do ##class(dc.test).test() {"items":[{"title":"For Whom the Bell Tolls","author":"Hemmingway"},{"title":"The Invisible Man","author":"Ellison"},{"title":"Tender is the Night","author":"Fitzgerald"}],"results":3}
go to post Vitaliy Serdtsev · May 28, 2020 Google the JDBC Driver for Excel. Here is a good option: HXTT Excel Pure Java JDBC (1.2, 2.0, 3.0, 4.0, 4.1, 4.2, 4.3) Drivers for MS Excel (XLS, XLSX)
go to post Vitaliy Serdtsev · May 22, 2020 Added several more types: Class dc.test [ Abstract ] { ClassMethod ValType(ByRef var) As %String { s a(-1)="undefined",a(0)="empty",a(1)="string",a(2)="integer",a(3)="float",a(4)="double",a(5)="object",a(6)="list",a(7)="array",a(8)="bitstring" s r=$s('$d(var):-1, $isobject(var):5, $d(var)>9:7, var="":0, $lv(var):6, $l(var)>254:1, 1:$tr($a($lb(var),2),1245678,1122334)) i r=1 { s s=##class(%Utility).FormatString(var) s:($f(s,"$c(")=4)||($f(s,"$zwc(")=6) r=8 } q a(r) } /// d ##class(dc.test).test() ClassMethod test() { s old=$system.Process.Undefined(2) try{ w ##class(%Utility).FormatString(undef)," => ",..ValType(.undef),! f i="","1",1,1.1,$double(1.1),##class(%ListOfDataTypes).%New(),$lb(),$factor(1),$c(7) { w ##class(%Utility).FormatString(i)," => ",..ValType(.i),! } s (i,i(1))="" w ##class(%Utility).FormatString(i)," => ",..ValType(.i),! }catch{ } d $system.Process.Undefined(old) } } Result: USER>d ##class(dc.test).test() "" => undefined "" => empty 1 => string 1 => integer 1.1 => float $double(1.1000000000000000888) => double "1@%Library.ListOfDataTypes" => object $lb() => list $zwc(128,4)_$c(1,0,0,0)/*$bit(1)*/ => bitstring $c(7) => bitstring "" => array
go to post Vitaliy Serdtsev · May 22, 2020 InterSystems IRIS Community Edition Limitations Also see %SYSTEM.License, e.g. method MaxConnections
go to post Vitaliy Serdtsev · May 20, 2020 Extending the reply of @Robert Cemper The following query compiles without errors, even though Studio highlights the error &sql(select :fieldname into :fieldvar from :tablename)Everything is fine in Caché: the error occurs at the compilation-time. In order for an error to occur in IRIS Studio too you need to use the flag /compileembedded=1 It is strange that the documentation mentions field name, but there is no mention of table name: A host variable cannot be used to pass a field name or keyword into an SQL statement. proof
go to post Vitaliy Serdtsev · May 20, 2020 In MUMPS, not everything is so simple, so specify technical task ;) Example: USER>set v1=1,v2="1" zzdump v1,v2 0000: 31 1 0000: 31 1 what to do with dates: 30000 is a number or date 20.02.1923? or "20.02.1923" - is it a date or a string? what about numbers: 0 is %TinyInt, %SmallInt, or %Integer? what about boolean: 1 is %Boolean or %Integer? In addition, you mix MUMPS (variable) and InterSystems ObjectScript (%Library.XXX): see Variable Types
go to post Vitaliy Serdtsev · May 20, 2020 It can be simpler: Property HowManyRecords As %Integer [ Calculated, ReadOnly, Required, SqlComputeCode = {n r,SQLCODE &sql(select count(*) into :r from schema_package.table) s {*}=$s(SQLCODE:-1,1:r)}, SqlComputed ];
go to post Vitaliy Serdtsev · May 18, 2020 Absolutely true. InterSystems SQL uses this index to improve performance of COUNT(*), which returns the number of records (rows) in the table. proof
go to post Vitaliy Serdtsev · May 18, 2020 Are a couple of points: The macro "ClassSQLTable" is defined in the method %Library.EnsembleMgr:UpgradeUTCIndices I would prefer to use ##class(%DeepSee.Utils).%GetSQLTableName(pClass As %String, pVerifyExists=0)
go to post Vitaliy Serdtsev · Apr 30, 2020 Unfortunately, there are errors in the methods GenExportBinaryStream/GenImportBinaryStream in the class %JSON.Generator.
go to post Vitaliy Serdtsev · Apr 30, 2020 Thank you for asking. It seems that no one has tried my code in all this time, or it's just that no one is interested in it. There are two ways to solve the issue: configure Undefined=2. I have historically set this value. This can be done programmatically or via SMP fix the code: ClassMethod NewQuery1Fetch( ByRef qHandle As %Binary, ByRef Row As %List, ByRef AtEnd As %Integer = 0) As %Status [ PlaceAfter = NewQuery1Execute ] { if qHandle>1 { set Row=qHandle($increment(qHandle,-1)) } else { set AtEnd=1 } quit $$$OK }
go to post Vitaliy Serdtsev · Apr 11, 2020 Example Class dc.test [ Abstract ] { /// Encode a stream as BASE64 ClassMethod Base64EncodeStream( pStream As %Stream.Object, Output pEncoded As %Stream.Object) As %Status { try{ $$$ThrowOnError(pStream.Rewind()) s pEncoded=##class(%Stream.TmpCharacter).%New() while 'pStream.AtEnd { s tLen=5700 s sc=pEncoded.Write($system.Encryption.Base64Encode(pStream.Read(.tLen))) return:$$$ISERR(sc) sc } s sc=pEncoded.Rewind() }catch(ex) { s sc=ex.AsStatus() } q sc } ClassMethod AESCBCBase64EncryptStream( Plaintext As %Stream.Object, Output Base64text As %Stream.Object, Key As %String, IV As %String) As %Status { try{ $$$ThrowOnError(Plaintext.Rewind()) s length=$$$MaxLocalLength, wasWide=$$$NO i $System.Version.IsUnicode() { while 'Plaintext.AtEnd && 'wasWide { s wasWide=$ZISWIDE(Plaintext.Read(length,.sc)) return:$$$ISERR(sc) sc } $$$ThrowOnError(Plaintext.Rewind()) } i wasWide { s tmp=##class(%IO.StringStream).%New() s tmp.CharEncoding="UTF8" d tmp.CopyFrom(Plaintext,,$$$YES,.sc) return:$$$ISERR(sc) sc s tmp.CharEncoding="Binary" $$$ThrowOnError(Plaintext.Clear()) $$$ThrowOnError(Plaintext.CopyFrom(tmp)) } s chiperstream=##class(%Stream.TmpCharacter).%New() $$$ThrowOnError($system.Encryption.AESCBCEncryptStream(Plaintext,chiperstream,Key,IV)) s sc=..Base64EncodeStream(chiperstream,.Base64text) }catch(ex) { s sc=ex.AsStatus() } q sc } /// d ##class(dc.test).Test() ClassMethod Test(plaintext = {"test"_$c(768)}) { s key=$tr($j("",16)," ","0"), IV="", plainstream=##class(%Stream.TmpCharacter).%New() d plainstream.Write(plaintext) ;w $system.Encryption.Base64Encode($system.Encryption.AESCBCEncrypt($zcvt(plaintext,"O","UTF8"),key,IV)),! d $system.OBJ.DisplayError(..AESCBCBase64EncryptStream(plainstream,.base64stream,key,IV)) w base64stream.Read(),! } } Result: USER>d ##class(dc.test).Test("test"_$c(68)) gTNg0UMkvQ3o+ehJkvr6lA== USER>d ##class(dc.test).Test("test"_$c(768)) R8UuZkjDVZidYckYMTpnVg== USER>d ##class(dc.test).Test("测试") lsYxFAQgNtiXHyaeGTWJ0A==
go to post Vitaliy Serdtsev · Apr 8, 2020 /// Encode a stream as BASE64 ClassMethod Base64EncodeStream( pStream As %Stream, Output pEncoded As %Stream) As %Status { s tSC=$$$OK try { s tSC=pStream.Rewind() q:$$$ISERR(tSC) s pEncoded=##class(%Stream.TmpCharacter).%New() while 'pStream.AtEnd { s tLen=5700 s tSC=pEncoded.Write($system.Encryption.Base64Encode(pStream.Read(.tLen))) q:$$$ISERR(tSC) } q:$$$ISERR(tSC) s tSC=pEncoded.Rewind() } catch (e) { s tSC=e.AsStatus() } q tSC }
go to post Vitaliy Serdtsev · Apr 2, 2020 Or something like that: Class dc.test Extends %Persistent { Property Name As %String; Property Age As %Numeric; Property City As %String; Property Phone As %String; /// d ##class(dc.test).Test() ClassMethod Test() { do ..%KillExtent() // This is your Data-Object... ;set data="",data=[],data=..%New() set data=[ {"Name":"Joe", "Age":44, "City":"Boston", "Phone":"1-234-4567"}, {"Name":"Ron", "Age":48, "City":"Dallas", "Phone":"1-234-5678"}, {"Name":"Eve", "Age":40, "City":"Miami", "Phone":"1-234-4567"}, ($listbuild("Tommy", 50, "New York", "1-345-6789")), ($listbuild("Alexa", 35, "Portland", "1-567-8901")) ] // Now insert all the above data into your table... &sql( INSERT INTO dc.test(Name,Age,City,Phone) SELECT $list(row,1),$list(row,2),$list(row,3),$list(row,4) FROM dc.DataProvider(:data) ) zwrite ^dc.testD // Now update your table... set data=[($listbuild("Vitaliy", 35, "Moscow", "1-999-1234"))] &sql( UPDATE dc.test t SET t.Name=obj.Name FROM (SELECT $list(row,1) Name,$list(row,2) Age FROM dc.DataProvider(:data)) obj WHERE t.Age=obj.Age ) zwrite ^dc.testD } Query NewQuery1(data) As %Query(ROWSPEC = "row:%List") [ SqlName = DataProvider, SqlProc ] { } ClassMethod NewQuery1Execute( ByRef qHandle As %Binary, data) As %Status { if $IsObject(data),data.%IsA("%Library.DynamicArray"),data.%Size() { set qHandle=data.%Size()+1 for i=1:1:data.%Size() { set r=data.%Get(i-1) if $IsObject(r) { set it=r.%GetIterator(),row="" while it.%GetNext(,.val) { set row=row_$listbuild(val) } } else { set row=r } set qHandle(qHandle-i)=$listbuild(row) } } quit $$$OK } ClassMethod NewQuery1Fetch( ByRef qHandle As %Binary, ByRef Row As %List, ByRef AtEnd As %Integer = 0) As %Status [ PlaceAfter = NewQuery1Execute ] { if qHandle { set Row=qHandle($increment(qHandle,-1)) } else { set AtEnd=1 } quit $$$OK } ClassMethod NewQuery1Close(ByRef qHandle As %Binary) As %Status [ PlaceAfter = NewQuery1Execute ] { quit $$$OK } Storage Default { <Data name="testDefaultData"> <Value name="1"> <Value>%%CLASSNAME</Value> </Value> <Value name="2"> <Value>Name</Value> </Value> <Value name="3"> <Value>Age</Value> </Value> <Value name="4"> <Value>City</Value> </Value> <Value name="5"> <Value>Phone</Value> </Value> </Data> <DataLocation>^dc.testD</DataLocation> <DefaultData>testDefaultData</DefaultData> <IdLocation>^dc.testD</IdLocation> <IndexLocation>^dc.testI</IndexLocation> <StreamLocation>^dc.testS</StreamLocation> <Type>%Storage.Persistent</Type> } } Result: USER>d ##class(dc.test).Test() ^dc.testD=5 ^dc.testD(1)=$lb("","Joe",44,"Boston","1-234-4567") ^dc.testD(2)=$lb("","Ron",48,"Dallas","1-234-5678") ^dc.testD(3)=$lb("","Eve",40,"Miami","1-234-4567") ^dc.testD(4)=$lb("","Tommy",50,"New York","1-345-6789") ^dc.testD(5)=$lb("","Alexa",35,"Portland","1-567-8901") ^dc.testD=5 ^dc.testD(1)=$lb("","Joe",44,"Boston","1-234-4567") ^dc.testD(2)=$lb("","Ron",48,"Dallas","1-234-5678") ^dc.testD(3)=$lb("","Eve",40,"Miami","1-234-4567") ^dc.testD(4)=$lb("","Tommy",50,"New York","1-345-6789") ^dc.testD(5)=$lb("","Vitaliy",35,"Portland","1-567-8901")
go to post Vitaliy Serdtsev · Mar 28, 2020 With your permission I will add some useful links on the topic: Here can find much more discussion of this project/idea: Declarative development in Caché Another implementation of Declarative ObjectScript: Looking for the equivalent of first-class functions in the Caché DBMS Discussion of this idea/approach on a Russian-language forum (link to machine translation): A declarative approach to the development
go to post Vitaliy Serdtsev · Mar 27, 2020 Using my simple example, when the method receive a name param or a age param to build the where clause. I really don't know how to solve it using query class. Query FilterBy( Name As %String = "", Age As %Integer = "") As %SQLQuery(CONTAINID = 1, SELECTMODE = "RUNTIME") [ SqlName = SP_Sample_Filter_By, SqlProc ] { SELECT TOP 5 ID, Name, Age, SSN FROM Sample.Person WHERE (nvl(:Name,'')='' or Name %STARTSWITH :Name) AND (nvl(:Age,'')='' or Age >= :Age) } Run Examples: select * from Sample.SP_Sample_Filter_By(,47) select * from Sample.SP_Sample_Filter_By('',47) select * from Sample.SP_Sample_Filter_By('s',47) select * from Sample.SP_Sample_Filter_By('s') select * from Sample.SP_Sample_Filter_By('s','')
go to post Vitaliy Serdtsev · Mar 19, 2020 SELECT NVL(order_description,'') || CASE WHEN NVL(dosage,'')='' OR NVL(dosage_unit,'')='' THEN '' ELSE ', ' || dosage || ' ' || dosage_unit || CASE WHEN NVL(dosage_form,'')='' THEN '' ELSE ' ' || dosage_form END || '' END || CASE WHEN NVL(administration_route,'')='' THEN '' ELSE ', ' || administration_route END || CASE WHEN NVL(frequency_description,'')='' THEN '' ELSE ', ' || CASE WHEN NVL(quantity,'')='' OR NVL(quantity_unit,'')='' THEN '' ELSE quantity || ' ' || quantity_unit || ' ' END || frequency_description END || IFNULL(start_date,'',', ' || 'Start Date: ' || CONVERT(SQL_DATE,start_date,101)) As MedicationOrder FROM CWSOrderEntry.history_client_order WHERE PATID='100068' --AND FACILITY=?FACILITY AND order_status_code='A' AND order_type_category_code='P'