Query related to set statement - mumps

what is the meaning of the S %%G=A(%%I) statement?

The statement S %%G=A(%%I) is not a valid statement in Standard MUMPS.
A related statement S %G=A(%I) is a valid statement in Standard MUMPS.
It is possible that an extension of Standard MUMPS might define a meaning for the first statement, but it isn't guaranteed to work on any system other than that implementation.
It is possible that the statement makes sense in EsiObjects or Intersystems Cache Object Script.
The related statement S %G=A(%I) means:
Command -> SET (Asssign a value to a variable)
left-hand side of SET -> %G simple temporary variable named %G accessible only from the current MUMPS job. This variable does not have to be defined, and if it is defined, any value associated with the local variable %G will be erased by the incoming value of the right hand side of the SET. (unless an error occurs)
right-hand side of SET -> A(%I) The current value of the simple temporary variable named %I which accessible only from the current MUMPS job is used as an index (or subscript) into the simple temporary array variable named A which is also accessible only from the current MUMPS job. Both %I and A at that array position must be defined.
Result of Command. The value of the local variable %I is used as an index into the local
variable A, retrieving the value at that array location. The value at that array location is then copied into the local variable %G.

Related

Error "attribute parameter is not in hash ref" when using Perl DBI selectall_hashref

I'm trying to get my first select to work using selectall_hashref from the Perl DBI module. I've opened a connection to the database (MySQL) successfully. I'm getting an error when I execute the following:
$dbh->selectall_hashref('SELECT id FROM users WHERE login=?',undef,"myusername");
DBI::st=HASH(0x1505a60)->_prepare(...): attribute parameter 'myusername' is not a hash ref at /usr/lib/x86_64-linux-gnu/perl5/5.20/DBD/mysql.pm line 238.
My table should be able to support this query, it has an id column and login column for each user.
The examples I've found for selectall_hashref show the ? substitution parameter being passed as the third parameter. The DBI documentation says that the second and third arguments should be %attr and #bind_values but doesn't give much documentation about them or show working examples.
What is causing the error, and more importantly how do you actually use the %attr and #bind_values correctly?
If you want to store everything as an arrayref where each row is a hashref (which is what your comment seems to indicate), you can use the selectall_arrayref() method with the Slice attribute:
$dbh->selectall_arrayref('SELECT id FROM users WHERE login=?', {Slice => {}}, 'myusername');
It's a little weird, but here's how it works:
If $slice is a hash reference, fetchall_arrayref fetches each row as
a hash reference. If the $slice hash is empty then the keys in the
hashes have whatever name lettercase is returned by default. (See
"FetchHashKeyName" attribute.) If the $slice hash is not empty,
then it is used as a slice to select individual columns by name. The
values of the hash should be set to 1. The key names of the returned
hashes match the letter case of the names in the parameter hash,
regardless of the "FetchHashKeyName" attribute.
It's a good idea to set the FetchHashKeyName attribute on the database handle to make your hash key names consistent; I happen to like NAME_lc in my applications.
The methods expects key column as the second parameter and attributes ref is passed as third one. In the result it builds a hash with the specified column as a key. What you probably want, is selectall_arrayref:
$ dbh->selectall_arrayref('SELECT id FROM users WHERE login=?',undef,"myusername");

Datatype mismatch error in ssis

I am retrieving some columns from some tables(below two are responsible for errors)
CUSTOMER_ID - numeric(9)
INCIDENT_ID - int(4)
and moving the results to foreach loop container(used derived transformation before moving results into record set i.e., CUSTOMER_ID - DT_NUMERIC,INCIDENT_ID - DT_I4) but i end up with these two errors
ForEach Variable Mapping number 3 to variable "User::CUSTOMER_ID" cannot be applied.
ForEach Variable Mapping number 6 to variable "User::INCIDENT_ID" cannot be applied.
The type of the value being assigned to variable "User::CUSTOMER_ID" differs from the
current variable type. Variables may not change type during execution. Variable types
are strict, except for variables of type Object.
The type of the value being assigned to variable "User::INCIDENT_ID" differs from
the current variable type. Variables may not change type during execution. Variable
types are strict, except for variables of type Object.
I tried isnull() to both columns but of no use, i googled alot but didnt overcome it.
Please help.
SSIS is unbeleivably fussy in this area.
When retrieving those columns, I would cast them as text e.g. NVARCHAR ( 50 ). Then the Variables used in the For Each Loop Container can use Data Type = String.

Why does SSIS TOKEN function fail to count adjacent column delimiters?

I ran into a problem with SQL Server Integration Services 2012's new string function in the Expression Editor called TOKEN().
This is supposed to help you parse a delimited record. If the record comes out of a flat file, you can do this with the Flat File Source. In this case, I am dealing with old delimited import records that were stored as strings in a database VARCHAR field. Now they need to be extracted, massaged, and re-exported as delimited strings. For example:
1^Apple^0001^01/01/2010^Anteater^A1
2^Banana^0002^03/15/2010^Bear^B2
3^Cranberry^0003^4/15/2010^Crow^C3
If these strings are in a column called OldImportRecord, the delimiter is a caret (as shown), and we wish to put the fifth field into a Derived Column, we would use an expression like:
TOKEN(OldImportRecord,"^",5)
This returns Anteater, Bear, Crow, etc. In fact, we can create Derived Columns for each of the fields in this record (note that the index is one-based), change them as needed, and then build another delimited record for export.
Here's the problem. What if some of our data includes some empty strings (or Nulls rendered as empty strings)?
4^^0004^6/15/2010^Duck^D4
The TOKEN() fails to count the adjacent column delimiters, which throws off the column count. Now it only sees five columns instead of six columns. Our TOKEN(OldImportRecord,"^",5) returns "D4" instead of the intended "Duck". When we extract the fourth column, we wind up trying to put "Duck" into a Date column, and all sorts of fun ensues.
Here's a partial workaround:
TOKEN(REPLACE(OldImportRecord,"^^","^ ^"),"^",5)
Notice this misses every second delimiter pair, so it will fail for a string like "5^^^^Emu^E5", which looks like"5^ ^^ ^Emu^E5" after the REPLACE(). The column count is still wrong.
So here's my full workaround. This includes two nested REPLACE statements(), an RTRIM() to remove the superfluous spaces, and a DT_STR cast because I would like to keep the result in VARCHAR:
(DT_STR,255,1252)RTRIM(TOKEN(REPLACE(REPLACE(OldImportRecord,"^^","^ ^"),"^^","^ ^"),"^",5))
I am posting this for information, since others may also run into this problem.
Does anyone have a better workaround, or even a real solution?
Reason for the issue:
TOKEN method in SSIS uses the implementation of strtok function in C++. I gathered this information while reading the book Microsoft® SQL Server® 2012 Integration Services. It is mentioned as note on page 113 (I like this book! Lots of nice information.).
I searched for the implementation of strtok function and I found the following links.
INFO: strtok(): C Function -- Documentation Supplement - The code sample in this link shows that the function does ignore consecutive delimiter characters.
The answers to the following SO questions point out that strtok function is designed to ignore consecutive delimiters.
Need to know when no data appears between two token separators using strtok()
strtok_s behaviour with consecutive delimiters
I think that the TOKEN and TOKENCOUNT functions are working as per design but whether that is how SSIS should behave might be a question for the Microsoft SSIS team.
Original Post - Above section is an update:
I created a simple package in SSIS 2012 based on your data inputs. As you had described in your question, the TOKEN function does not behave as intended. I agree with you that the function doesn't seem to work. This post is not an answer to your original issue.
Here is an alternative way to write the expression in a relatively simpler fashion. This will only work if the last segment in your input record will always have a value (say A1, B2, C3 etc.).
Expression can be rewritten as:
This statement will take the input record as the parameter, the delimiter caret (^) as the second parameter. The third parameter calculates the total number segments in the records when split by the delimiter. If you have data in the last segment, you are guaranteed to have two segments. You can then subtract 1 to fetch the penultimate segment.
(DT_STR,50,1252)TOKEN(OldImportRecord,"^",TOKENCOUNT(OldImportRecord,"^") - 1)
I created a simple package with data flow task. OLE DB source retrieves the data and the derived transformation parses and splits the data as per the screenshot below. The output is then inserted into the destination table. You can see the source and destination tables in the last screenshot. Destination table has two columns. The first column stores the penultimate segment data and the segments count based on the delimiter (which again isn't correct). You can notice that the last record didn't fetch the correct results. If the last record didn't have the value 8, then the above expression will fail because the expression will evaluate to zero index.
Hope that helps to simplify your expression.
If you don't hear from anyone else, I would recommend logging this issue in Microsoft Connect website.
Create table and populate scripts:
CREATE TABLE [dbo].[SourceTable](
[OldImportRecord] [varchar](50) NOT NULL
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[DestinationTable](
[NewImportRecord] [varchar](50) NOT NULL,
[CaretCount] [int] NOT NULL
) ON [PRIMARY]
GO
INSERT INTO dbo.SourceTable (OldImportRecord) VALUES
('1^Apple^0001^01/01/2010^Anteater^A1'),
('2^Banana^0002^03/15/2010^Bear^B2'),
('3^Cranberry^0003^4/15/2010^Crow^C3'),
('4^^0004^6/15/2010^Duck^D4'),
('5^^^^Emu^E5'),
('6^^^^Geese^F6'),
('^^^^Pheasant^G7'),
('8^^^^Sparrow^');
GO
Derived column transformation inside data flow task:
Data in source and destination tables:
Not only does TOKEN skip adjacent delimiters, it also skips leading and trailing delimiters as well. So, using your example, if you had a field "good" field that looks like this:
1^Apple^0001^01/01/2010^Anteater^A1
Followed by one with adjacent and leading delimiters like this:
^^^0004^6/15/2010^Duck^
TOKENCOUNT would only find two delimiters and you'd end up with 0004 assigned to Token1, 6/15/2010 for Token2, and Duck for Token3.
I used a different kind of replace. Rather than placing spaces between adjacent delimiters, which wouldn't help with leading or training, I used replace to surround the delimiters with characters I absolutely wouldn't find in my text. The following Expression works well for me. It's wordy, but it is what it is.
(DT_STR,255,1252)REPLACE(TOKEN(REPLACE(OldImportRecord,"^","~^~"),"^",1),"~","")
Of course, you'd replace the number 1 with whatever Token you wanted and adjust the cast according to your needs. Hope that helps.

Detecting the value 0x in a varchar column sourced from Excel

I have a sql table that gets populated via SQLBulkCopy from Excel. The copy down is done using the Microsoft ACE drivers.
I had a problem with one particular file - when it was loaded down to sql, some of the columns (which appear empty in excel) contained an odd value.
For example, running this sql:
SELECT
CONVERT(VARBINARY(10),MyCol),
LEN(MyCol)
FROM MyTab
would return
0x, 0
i.e. - converting the value in the column to varbinary shows something, but doing length of the varchar shows no length. I realise that the value shown is the stem of a hex value, but its weird that its gets there, and how hard it is to detect.
Obviously I can just clear out the cells in Excel, but I really need to detect this automatically as end users will have the same issue. It is causing issues further down the line when the data gets processed. Its quite hard to trace the problem back from its eventual symptoms to being this issue in the source.
Other than the above conversion to varbinary to output in SSMS I've not come up with a way of detecting these values, either in Excel or via a SQL script to remove them.
Any ideas?
This may help you:
-- Conversion from hex string to varbinary:
DECLARE #hexstring VarChar(MAX);
SET #hexstring = 'abcedf012439';
SELECT CAST('' AS XML).Value('xs:hexBinary( substring(sql:variable("#hexstring"), sql:column("t.pos")) )', 'varbinary(max)')
FROM (SELECT CASE SubString(#hexstring, 1, 2) WHEN '0x' THEN 3 ELSE 0 END) AS t(pos)
GO
-- Conversion from varbinary to hex string:
DECLARE #hexbin VarBinary(MAX);
SET #hexbin = 0xabcedf012439;
SELECT '0x' + CAST('' AS XML).Value('xs:hexBinary(sql:variable("#hexbin") )', 'varchar(max)');
GO
One method is to add a new column, convert the data, drop the
old column and rename the new column to the old name.
As Martin points out above, 0x is what you get when you convert an empty string. eg:
SELECT CONVERT(VARBINARY(10),'')
So the problem of detecting it obviously goes away.
I have to assume that there is some rubbish in the excel cell, that is being filtered out in the process of the write down by either the ACE driver or the SQLBulkCopy. Because there was something in the field originally, the value written is empty instead of null.
In order to make sure that everything is consistent in the data we'll need to do a post process to switch all empty values to nulls so that the next lots of scripts work.

Does the mysql CLI tool provide a way to display binary data in a console-friendly manner?

I have a MySQL database containing a table with a binary-typed column. I'd like to be able to project that column without having to run it through, e.g., HEX(). Does the mysql CLI tool have a configuration option or other means to display a representation of binary data in a manner that won't output arbitrary bytes for my console to interpret in hilarious/annoying ways?
Start MySQL CLI with param --binary-as-hex
Example:
mysql --binary-as-hex
Set mysql client options in /etc/my.cnf works for me:
[client]
binary-as-hex = true
[mysql]
binary-as-hex = true
Since you want to look at the table mostly for convenience, create a view:
CREATE OR REPLACE VIEW myview AS
SELECT col1, HEX(col2) AS col2, col3, etc....
FROM table;
Then, all you have to do is reference myview instead of table:
SELECT * FROM myview;
The behavior of the MySQL command line client when viewing result sets with binary data has always been an annoyance to me, in fact I found this page because I was once again annoyed by the MySQL command line client (dumping binary data into my terminal when looking at a result set with binary UUID columns) and I wanted to solve the issue once and for all :-)
Creating views really isn't an option for me (I'm looking at dozens of tables with binary UUID columns) and I also found that it's really annoying to switch from SELECT * to typing out all of the column names instead (just so HEX() can be applied to the value of one column).
Eventually I came up with a creative hack that provides inspiration for alternative solutions to this annoyance: Using a custom pager command to sanitize output for terminal rendering. Here's how it works:
Create an executable (chmod +x) Python script with the following contents:
#!/usr/bin/python
import binascii, string, sys
for line in sys.stdin:
line = line.rstrip()
column, _, value = line.partition(': ')
if any(c not in string.printable for c in value):
sys.stdout.write("%s: %s\n" % (column, binascii.hexlify(value)))
else:
sys.stdout.write("%s\n" % line)
Start the MySQL command line client as follows:
$ mysql --pager=/home/peter/binary-filter.py --vertical ...
Change the pathname of the Python script as applicable. You can also put the script in your $PATH, in that case you can just pass the name to the --pager option (similar to how you would use less as a pager for the MySQL client).
Now when you SELECT ..., any line that shows a column whose value contains non-printable characters is rewritten so that the complete value is rendered as hexadecimal characters, similar to the results of MySQL's HEX() function.
Disclaimer: This is far from a complete solution, for example the Python snippet I showed expects SELECT ... \G format output (hence the --vertical option) and I tested it for all of five minutes so it's bound to contain bugs.
My point was to show that the problem can be solved on the side of the MySQL command line client, because that's where the problem is! (this is why it feels backwards for me to define server side views - only to make a command line client more user friendly :-P)
For me there is no problem with database size, so I will use two different column in every table, one as binary(16), and the second as char(32) without indexing. both of them will have the same value.
when I need to search I will use binary column, and when I need to read I will use char(32).
is there any problem with this scenario?