Tableau MarkLogic Data Modelling - tableau-api

I am using Tableau with MarkLogic. I have the following XML Structure
<CustomerInformation CustomerId="1">
<CustomerBasicInformation>
<CustomerTitle></CustomerTitle>
<CustomerFirstName></CustomerFirstName>
<CustomerMiddleName></CustomerMiddleName>
<CustomerLastName></CustomerLastName>
</CustomerBasicInformation>
<CustomerEmplyomentDetails>
<CustomerEmployer>
<EmployerName IsCurrentEmployer=""></EmployerName>
<CustomerDesignation></CustomerDesignation>
<EmployerLocation></EmployerLocation>
<CustomerTenure></CustomerTenure>
</CustomerEmployer>
<CustomerEmplyomentDetails>
<PolcyDetails>
<Policy PolicyId="">
<PolicyName></PolicyName>
<PolicyType></PolicyType>
<PolicyCategory></PolicyCategory>
<QuoteNumber></QuoteNumber>
<PolicyClaimDetails>
<PolicyClaim ClaimId="">
<PolicyClaimedOn></PolicyClaimedOn>
<PolicyClaimType></PolicyClaimType>
<PolicyClaimantName></PolicyClaimantName>
</PolicyClaim>
</PolicyClaimDetails>
<PolicyComplaintDetails>
<PolicyComplaint ComplaintId="">
<PolicyComplaintStatus></PolicyComplaintStatus>
<PolicyComplaintOn></PolicyComplaintOn>
</PolicyComplaint>
</PolicyComplaintDetails>
<BillingDetails>
<Billing BillingId="">
<BillingAmount></BillingAmount>
<BillingMode></BillingMode>
</Billing>
</BillingDetails>
</Policy>
<Policy PolicyId="">
<PolicyName></PolicyName>
<PolicyType></PolicyType>
<PolicyCategory></PolicyCategory>
<QuoteNumber></QuoteNumber>
<PolicyClaimDetails>
<PolicyClaim ClaimId="">
<PolicyClaimedOn></PolicyClaimedOn>
<PolicyClaimType></PolicyClaimType>
<PolicyClaimantName></PolicyClaimantName>
</PolicyClaim>
</PolicyClaimDetails>
<PolicyComplaintDetails>
<PolicyComplaint ComplaintId="">
<PolicyComplaintStatus></PolicyComplaintStatus>
<PolicyComplaintOn></PolicyComplaintOn>
</PolicyComplaint>
</PolicyComplaintDetails>
<BillingDetails>
<Billing BillingId="">
<BillingAmount></BillingAmount>
<BillingMode></BillingMode>
</Billing>
</BillingDetails>
</Policy>
</PolcyDetails>
</CustomerInformation>
I have created a view on above structure.
Initially I have created a single view for all elements, but on Tableau I got duplicate values as well as Cartesian join result.
So to tackle this, I used approach of fragment root.
Since there can be multiple PolicyDetails for single customer. I have created fragment root on Policy.
Similarly Claims, Complaints, Billing, Quote can be multiple for single policy, I have created fragment root on each one of them.
Now after doing this it resolves the duplicate issue as well as Cartesian join result set. It gives unique set of record for each entities (CustomerInfo, Policy, Claims, Complaints, Quote, Employer, Billing).
However I am not able to relate this entities with each other (as in foreign-primary key).
I have created the following view with element scope and all. I am pasting only Customer and Policy details, if this resolves other entities can be similarly managed
view:create(
"InsurancePOC",
"CustomerBasicInfo",
view:element-view-scope(xs:QName("CustomerInformation")),
(
view:column("CustomerId", cts:element-attribute-reference(xs:QName("CustomerInformation"), xs:QName("CustomerId"))),
view:column("PolicyId", cts:element-attribute-reference(xs:QName("Policy"), xs:QName("PolicyId"))),
view:column("QuoteNumber", cts:element-attribute-reference(xs:QName("Quote"), xs:QName("QuoteNumber"))),
view:column("ComplaintId", cts:element-attribute-reference(xs:QName("PolicyComplaint"), xs:QName("ComplaintId"))),
view:column("BillingId", cts:element-attribute-reference(xs:QName("Billing"), xs:QName("BillingId"))),:)
view:column("CustomerFirstName", cts:element-reference(xs:QName("CustomerFirstName"))),
view:column("CustomerLastName", cts:element-reference(xs:QName("CustomerLastName")))
),
(),
()
),
view:create(
"InsurancePOC",
"PolcyInfo",
view:element-view-scope(xs:QName("Policy")),
(
view:column("PolicyId", cts:element-attribute-reference(xs:QName("Policy"), xs:QName("PolicyId"))),
view:column("PolicyName", cts:element-reference(xs:QName("PolicyName"))),
view:column("PolicyType", cts:element-reference(xs:QName("PolicyType")))
),
(),
()
)
All pre-requisites like element-range index and all is been done.
I am trying to relate these entities using view:column("PolicyId", cts:element-attribute-reference(xs:QName("Policy"), xs:QName("PolicyId"))) in CustomerBasicInfo view.
If I do so it shows zero results in Tableau or Query console.
If I remove it, gives unique record but without any relationship with each other.
All I want is to achieve relationship between Policy-Customer
Kindly go through the code snippet, if more clarification required please let me know

The getting of cartesian join results is a known issue with the SQL views driven from Range indexes in MarkLogic, particularly with aggregate docs like above.
The simplest way to solve it for SQL views would be to split your docs into separate Policies, with embedded copies of the customer into. That could mean a fair amount of data duplication if customers often have multiple policies.
You could also consider taking these docs apart, and storing policies and customer details separately, with id refs from policy to customer, so that you can join them together afterwards, in Tableau, or SQL.
MarkLogic 9 comes with a new feature though, that would prevent the need for all this. It is called Template Driven Extraction. It also provides SQL views on data, but works in a different way. It is driven with a match pattern (called the context) that controls the rows in the view. You would use Policy as context in this case. From there you would use relative paths to go up the tree to customer details, and down to get policy details.
TDE templates are installed using tde:template-insert. The documentation of that function shows a simple example of such a TDE:
http://docs.marklogic.com/tde:template-insert
You can also play around with tde:node-data-extract first, to get the hang of it.
HTH!

Related

Unique form with many tables

I'm trying to create a form to fill three tables to describe some projects with the 'Title of the project' as common field. When I create the form I have to write the title three times, otherwise it's not posible to fill the tables. Is there any way to put just one of the three fields on the form but the three of them are filled?
The database is empty, I want to make a form to start introducing all the projects that are going to be done in my group of work. In one table there are data related to the project, like start dat , full budget etc. In another one the information about my company, like the group its doing it, its role etc. In the last one just some general information like related tags. The name of the project appears in all of them, but when I do the form from a query they seem not to be related even if I do it on the query.
I've already tried to do it with the Wizard tool, selecting the different tables and its fields. I also tried to check the form properties...but I can't come up with what I'm doing wrong...
I'm new using access...

Prioritise which identifier to use

My crystal report pulls data about books, including an identifier (isbn, issn order number etc.), author, and publisher.
The ID field stores multiple ways to identify the book. The report displays any of the identifiers for that record. If one book has two identifiers; issn and order number, the report currently displays one apparently at random.
How can I make it prioritise which type to use based on a preset order? I figured some sort of filter on the field could work, but I haven't figured out how. I can't edit the table, but I can use SQL within the report.
If all the different types of ID are stored in a single field, your best bet is to use a SQL Command inside your report to separate them into multiple virtual fields.
Go to Database Fields / Database Expert, expand the connection you want to use, and pick Add Command. From here you can write a custom SQL statement to grab the information you're currently using, and at the same time separate the ID field into multiple different fields (as far as the report will be concerned, anyway. The table will stay unchanged.)
The trick is to figure out how to write your command to do the separation. We don't know what your data looks like, so you're on your own from here.
Based on the very little information that you have provided and if i was to make a guess.I suggest you make use of the formula field in your report and then use something like this to accomplish your goal.
IF ISNULL{first_priority_field_name} OR {first_priority_field_name} = '' THEN
{second_priority_field_name}
ELSE
{first_priority_field_name}
Use nested IF statement in case there are more than 2 identifier fields.

Using a query to supply an Access form

I have a Microsoft Access form that is being supplied (somehow) by a query. The query contains three tables linked together via their respective primary and foreign keys, and the form displays data quite happily.
The strange thing (as far as I'm concerned) is the ability of the form to then allow data entry using the query.
However, if the user creates a new record, the whole thing seems to have problems due to a required field in the [table2] table.
SELECT [table1].*
,[table2].JobNo
,[table2].PlannedDateOC
,[table3].DateJobStarted
,[table1].PlanNo
FROM (
[table1] LEFT JOIN [table2] ON [table1].PlanNo = [table2].PlanNo
)
LEFT JOIN [table3] ON [table2].JobNo = [table3].JobNo
ORDER BY [table2].PlannedDateOC
,[table1].PlanNo;
According to the users, this form worked perfectly prior to conversion from Access 97/2003 format to Access 2010 (2007 file format).
Could anyone clarify whether this (the fact that it should work) is legitimate, and if this process would work in either version of Access, if so? The concept of being able to use a query for data entry is quite alien to me.
Let me know if you need further clarification.
NOTE:
One thing of note, here, is that I did move some of the fields into the form header so that they were always visible as the rest of the form scrolls. I don't know if this will have any side effects on the performance of the form.
Above query will allow you to insert data into [table1] when all not null fields have their values and make sure only table1.fields are getting dirty when new record is inserted.

Report filter on 1-to-many joined tables

I have a report that shows maintenance information for medical instruments. The selection criteria are based on several tables and fields. I needed to change the criteria, but results were not as expected. I managed to find the cause, but do not know what to do to get to the wanted situation.
So basically the problem is as follows:
I have 2 tables that are linked:
* Equipment (information related to a specific instrument eg EqmId)
* ObjectFeature (information related to a specific feature eg ObjfEqmId, ObjfId, ObjfYesno)
An equipment can have 0, 1 or many ObjectFeatures, and the tables are linked via
Equipment.EqmId -> ObjectFeature.ObjfEqmId with a left-outer join.
The problem I have is that i want to filter out al EqmId's where (ObjfId="64" and ObjfYesno=1). I do not want to see these EqmId's in the final list.
In my current setup, I have only removed the ObjfId="64" lines, but since an EqmId can have multiple features, it still is present in the list...
In my original report Equipment is my main table, so I need a way to filter this table before I do further filtering and joining.
I find myself limited in the selection formula, and thought of using a SQL command on the database. But I can't get my head around how to do this.
How and where should I do the filtering?

coldfusion - bind a form to the database

I have a large table which inserts data into the database. The problem is when the user edits the table I have to:
run the query
use lots of lines like value="<cfoutput>getData.firstname#</cfoutput> in the input boxes.
Is there a way to bind the form input boxes to the database via a cfc or cfm file?
Many Thanks,
R
Query objects include the columnList, which is a comma-delimited list of returned columns.
If security and readability aren't an issue, you can always loop over this. However, it basically removes your opportunity to do things like locking certain columns, reduces your ability to do any validation, and means you either just label the form boxes with the column names or you find a way to store labels for each column.
You can then do an insert/update/whatever with them.
I don't recommend this, as it would be nearly impossible to secure, but it might get you where you are going.
If you are using CF 9 you can use the ORM (Object Relation Management) functionality (via CFCs)
as described in this online chapter
https://www.packtpub.com/sites/default/files/0249-chapter-4-ORM-Database-Interaction.pdf
(starting on page 6 of the pdf)
Take a look at <cfgrid>, it will be the easiest if you're editing table and it can fire 1 update per row.
For security against XSS, you should use <input value="#xmlFormat(getData.firstname)#">, minimize # of <cfoutput> tags. XmlFormat() not needed if you use <cfinput>.
If you are looking for an easy way to not have to specify all the column names in the insert query cfinsert will try to map all the form names you submit to the database column names.
http://help.adobe.com/en_US/ColdFusion/9.0/CFMLRef/WSc3ff6d0ea77859461172e0811cbec22c24-7c78.html
This is indeed a very good question. I have no doubt that the answers given so far are helpful. I was faced with the same problem, only my table does not have that many fields though.
Per the docs EntityNew() the syntax shows that you can include the data when instantiating the object:
artistObj = entityNew("Artists",{FirstName="Tom",LastName="Ron"});
instead of having to instantiate and then add the data field by field. In my case all I had to do is:
artistObj = entityNew( "Artists", FORM );
EntitySave( artistObj );
ORMFlush();
NOTE
It does appear from your question that you may be running insert or update queries. When using ORM you do not need to do that. But I may be mistaken.