Can not join Exact Online's Bill of Material Items and Items itself - exact-online

When I run the following query to retrieve item details on items in the Bill of Materials (BOM) of Exact Online, I get no item details:
select *
from BillOfMaterialItemDetails bom
join ExactOnlineREST..items itm
on itm.ID = bom.item_id_attr
However, when I execute this, I do get item information:
select *
from BillOfMaterialItemDetails bom
join ExactOnlineREST..items itm
on itm.code = bom.item_code_attr
Why is the join on the GUID in ID failing to find matches?

For some unknown reason, the Exact Online API have a different representation for a GUID in the REST and the XML API. You need to manually convert them yourself between '{GUID}' and 'GUID' as in:
select *
from BillOfMaterialItemDetails bom
join ExactOnlineREST..items itm
on itm.ID = replace(replace(bom.item_ID_attr, '{', ''), '}', '')

Related

MySQL complicated query | extracting a phrase from table of words

I'm working through MySQL connector in python on a project where I'm analyzing books.
I would gladly accept any help with my issue (explained below).
The relevant DB structures:
each Word, in each book, has its own word_id(primary key) and text.
each Word_instance has word_id, word_serial, offset in line, sentence number and so on...
the entity Word_instance's word_serial is its offset from the beginning of the book.
each Phrase has its own id and text.
each Phrase_word has phrase_id and word_id(from above).
Right now, I'm trying to figure out how to build a query that will locate a phrase from the user in the database.
Words are a part of a phrase if they have consecutive word_serial and are in the same sentence.
so far I've managed to build the following mess of a query:
select book_id
, word_txt
, word_serial
, sentence_serial
, ROW_NUMBER() Over (partition by sentence_serial, book_id) as encounter_num
from word
join word_instance
on word.word_id = word_instance.word_id
join word_in_phrase
on word.word_id = word_in_phrase.word_id
where phrase_id = %s
order
by book_id
, sentence_serial
, word_serial
In the following table image is the result set of said query.
let's say the user has entered the phrase: "I believe in cause".
in that case I would need to extract word_serial = 562, as it is the beginning said phrase.
can I accomplish such a task without extracting row by row and assessing whether the current row is part of the phrase and in the correct order?
In fact, there are way to many rows to examine outside of SQL to consider that a possibility.
I will appreciate your help immensely, as I'm stuck on this issue for far too long...
As requested, I'm uploading images of relevant DB entities:
Word_in_phrase entity
Word_instance entity
word entity
This probably isn't the most efficient way of writing this, but I think it works in principle and you could tinker with it as you wanted. Note that I assumed phrases can't cross sentence boundaries (wi2.sentence_serial = wi1.sentence_serial) and I've assumed a column word_in_phrase.order_id exists that starts at 0 and increases by 1 for each word. I'm also assuming word_id increases by 1 each row. (You could make those assumptions true by using CTEs where that is true instead of the real tables).
with (
SELECT *
FROM word_in_phrase
WHERE phrase_id = %s
) as phrase
select book_id
, word_txt
, word_serial
, sentence_serial
from word
join word_instance wi1
on word.word_id = word_instance.word_id
where (SELECT COUNT(*) FROM phrase) = (SELECT COUNT(*) FROM word_instance wi2 INNER JOIN phrase on wi2.word_id = phrase.word_id WHERE wi2.book_id = wi1.book_id and wi2.sentence_serial = wi1.sentence_serial and wi2.word_id = wi1.word_id + phrase.order_id)
order
by book_id
, sentence_serial
, word_serial
Alternatively, you might prefer something like
with (
SELECT *
FROM word_in_phrase
WHERE phrase_id = %s
) as phrase
select wi1.book_id
, word_txt
, wi1.word_serial
, wi1.sentence_serial
from word
join word_instance wi1
on word.word_id = word_instance.word_id
inner join word_instance wi2
on wi2.book_id = wi1.book_id and wi2.sentence_serial = wi1.sentence_serial
INNER JOIN phrase
on wi2.word_id = phrase.word_id
WHERE wi2.word_id = wi1.word_id + phrase.order_id
GROUP BY
wi1.book_id
, word_txt
, wi1.word_serial
, wi1.sentence_serial
HAVING COUNT(*) = (SELECT COUNT(*) FROM phrase)

Return a different datatype from postgresql

I have the below query in PG
SELECT
project.project_id,
project.project_name,
category.category_name,
array_agg(row(skill.skill_name,projects_skills.projects_skills_id)) AS skills
FROM project
JOIN projects_skills ON project.project_id = projects_skills.project_id
JOIN skill ON projects_skills.skill_id = skill.skill_id
JOIN category ON project.category_id = category.category_id
GROUP BY project.project_name,project.project_id, category.category_name;
of particular interest is the below line which seems to return a pseudo-type tuple
array_agg(row(skill.skill_name,projects_skills.projects_skills_id)) AS skills
I'm unable to create a view of this because of the pseudo type - in addition to this, the row function seems to return a tuple set like the below:
skills: '{"(Python,3)","(Node,4)","(Javascript,5)"}' }
I could painfully parse it in JavaScript by replacing '(' to '[' etc. but could I do something in postgres to return it preferably as an object?
One possible solution is to register a row type (once):
CREATE TYPE my_type AS (skill_name text, projects_skills_id int);
I am guessing text and int as data types. Use the actual data types of the underlying tables.
SELECT p.project_id, p.project_name, c.category_name
, array_agg((s.skill_name, ps.projects_skills_id)::my_type) AS skills
FROM project p
JOIN projects_skills ps ON p.project_id = ps.project_id
JOIN skill s ON ps.skill_id = s.skill_id
JOIN category c ON p.category_id = c.category_id
GROUP BY p.project_id, p.project_name, c.category_name;
There are many other options, depending on your version of Postgres and what you need exactly.
As well as the excellent suggestions to use JSON in the comments, and #Erwin 's to use a registered composite type, you can use a two-dimension array, or a multivalues approach:
Just replace your line
array_agg(row(skill.skill_name::text,projects_skills.projects_skills_id::text)) AS skills
with the following:
Two dimension array option 1
array_agg(array[skill.skill_name::text,projects_skills.projects_skills_id::text]) AS skills
-- skills will be '{{Python,3},{Node,4},{Javascript,5}}', thus
-- skills[1][1] = 'Python' and skills[1][2] = '3' -- id is text
Two dimension array option 2
array[array_agg(skill.skill_name),array_agg(projects_skills.projects_skills_id)] AS skills
-- skills will be '{{Python,Node,Javascript},{3,4,5}}', thus
-- skills[1][1] = 'Python' and skills[2][1] = '3' -- id is text
Multivalues
array_agg(skill.skill_name) AS skill_names,
array_agg(projects_skills.projects_skills_id) AS skills_ids
-- skills_names = '{Python,Node,Javascript}' and skill_ids = '{3,4,5}', thus
-- skills_names[1] = 'Python' and skills_ids[1] = 3 -- id is integer

MySQL Query - Object Queuing Based on Object Property to Skill Mapping

Okay, so I know the title is a bit cryptic so I'll do what I can to explain the "problem" I have and the solution I am currently using.
Problem:
An 'object' of work needs to be distributed to the apropriate user based on said object's properties.
The idea is that there is an object of work has properties. Those properties are mapped to skills. A user has skills and is able to work on an object which is within the user's skillset.
There are several [three] property definitions and I currently have the following table structures.
|-- Object to Property Set 1 -- Property Set 1 to Skill --|
Object Table -|-- Object to Property Set 2 -- Property Set 2 to Skill --|-- User Skill -- User Table
|-- Object to Property Set 3 -- Property Set 3 to Skill --|
The query may be a bit easier to understand:
SELECT counts.object_id,
COUNT(DISTINCT counts.object_skill) object_skill_count,
COUNT(DISTINCT counts.user_skill) user_skill_count
FROM
(SELECT object.object_id,
sp.skill_id object_skill,
us.skill_id user_skill
FROM object_table object
LEFT JOIN object_property op ON op.object_id = object.object_id
LEFT JOIN skill_property sp ON sp.property_id = op.property_id
LEFT JOIN user_skill us ON us.skill_id = sp.skill_id
AND us.active = 1
AND us.user_id = {$userid} -- <=- inserted from a PHP script
AND object.state = 1
UNION SELECT object.object_id,
sf.skill_id object_skill,
us.skill_id user_skill
FROM object_table object
LEFT JOIN object_flag obf ON obf.object_id = object.object_id
LEFT JOIN skill_flag sf ON sf.flag_id = obf.flag_id
LEFT JOIN user_skill us ON us.skill_id = sf.skill_id
AND us.active = 1
AND us.user_id = {$userid} -- <=- inserted from a PHP script
AND object.state = 1
UNION SELECT object.object_id,
svf.skill_id object_skill,
us.skill_id user_skill
FROM object_table object
LEFT JOIN object_creator oc ON oc.creator_id = object.creator_id
LEFT JOIN skill_creator sc ON sc.flag_id = oc.flag_id
LEFT JOIN user_skill us ON us.skill_id = sc.skill_id
AND us.active = 1
AND us.user_id = {$userid} -- <=- inserted from a PHP script
AND object.state = 1) counts
GROUP BY counts.object_id
Here we get a count of all the skills an object as well as count the number of skills the user has on that same object. If the two counts match, we know the user can work on the object. If the object's skill count exceeds the user's count, the object is beyond the user's capabilities and will not be assigned to that user.
While the above query works, it slows significantly when thrown at a large[r] table. Would like to know if there is a better way of doing things. And, since the internet is filled with amazing people, here we are.
Retroactive Update:
The Left joins in this case are there because objects can have no properties. This equates to the count 0-0 and thus makes the object workable by anyone.
It looks ok. Conditions placed on data joins instead of where clause, no order by's.
Possible options:
1) Check for missing indexes
http://basitaalishan.com/2013/03/13/find-missing-indexes-using-sql-servers-index-related-dmvs/
2) Change 'left joins' to 'inner joins'
INNER JOIN vs LEFT JOIN performance in SQL Server
3) Use 'UNION ALL' instead of 'Union'
performance of union versus union all

How to use MSSQL to Row concatenate?

I know this row concatenation question has been asked before but I cannot find answers that will solve my problem. I have an older AS400/DB2 database that I am using an Excel ODBC connector to get to the data. I have used MySQL in the past but this is my firstt attempt at MSSQL. To set up the question I have the following:
A work order number (wono)
A note line number (ntlno1)
A note data 50 character text length (ntda)
For each wono you can have several line numbers (ntlno1) and each line number can have up to 50 characters of data (ntda). I need to be able to concatenate all of the ntda data into one field by work order number and note line number. Here is what I have so far:
SELECT
DISTINCT WOHDR.wono AS WONO, WONOT.ntlno1 AS NoteLineNo, substring((Select ','+WONOT.ntda AS [text()]
From libd09.wopnote0 WONOT
Where WONOT.wono = WOHDR.wono
ORDER BY WONOT.wono
For XML PATH ('')),2, 1000) [wopnote0]
FROM libd09.wophdrs0 WOHDR
LEFT JOIN libd09.wopsegs0 WOSEG ON (WOHDR.wono = WOSEG.wono)
LEFT JOIN libd09.cslusrp0 USR ON (WOSEG.clsdby = USR.uspfid)
LEFT JOIN libd09.woplabr0 WOLBR ON (WOHDR.wono = WOLBR.wono)
LEFT JOIN libd09.wopnote0 WONOT ON (WOHDR.wono = WONOT.wono)
LEFT JOIN libd09.wopmisc0 WOMISC ON (WOHDR.wono = WOMISC.wono)
LEFT JOIN libd09.wopempf0 WOEMP ON (WOMISC.epidno = WOEMP.epidno)
LEFT JOIN libd09.woppart0 WOPART ON (WOHDR.wono = WOPART.wono)
LEFT JOIN tafilev22.employ01 TAEMP ON (WOMISC.epidno = TAEMP.ememp)
WHERE WOHDR.opndt8 BETWEEN ? AND ?
I have only included the pertinent columns though the joins have all the tables that I need. when I run the query I get the following error: Token [ was not valid. Valid tokens: .
I am sure I am missing something simple so any advice or help would be greatly appreciated.

Wordpress Search Serialized Meta Data with Custom Query

I'm trying to do a search on serialized post meta values in a wordpress database. I know the structure of the serial string so I can search for the preceding value, get the index and then get the number of characters I want before that index value. I cannot effectively use regexp in this particular query because I would like to sort based on the results. This is what I have so far, but I am failing on the syntax and I think it has to do with trying to use the AS keyword and my grouping the AND statements.
SELECT SQL_CALC_FOUND_ROWS _posts.ID FROM _posts
INNER JOIN _postmeta ON (_posts.ID = _postmeta.post_id)
WHERE 1=1
AND _posts.post_type = 'dog'
AND (_posts.post_status = 'publish')
AND ( (_postmeta.meta_key = '_meta_general'
AND CAST(_postmeta.meta_value AS CHAR)) AS dmet
AND POSITION(';s:6:\"weight' IN dmet) AS ddex
AND MID(dmet ,ddex,10)) AS dres
GROUP BY dres ORDER BY dres ASC LIMIT 0, 10
Well, I'm still having issues with the structure of this thing. The previous code did not work, #fenway, after closer inspection. Here is what I have now. The problem with #fenway's answer is that the MID and POSITION values were being called in the select part of the statement that was selecting "FROM" posts. They are located in postmeta. So I attempted to rearrange the string filtering after the INNER JOIN which is joining the postmeta table to the posts table by id. This is not working. I understand that this question is simply due to a lack of my knowledge in SQL, but I'm trying to learn here.
None of these are working as I want. There are syntactical errors. The purpose of the code is to group the returned query by a value that is inside of a serial(json) string. The method is to search for the following value (n this case it would be - ";s:6:"weight -) When I have the index of this string I want to return the preceding 10 values ( a date xx/xx/xxxx ). I want to label this string (AS dres) and have the result sort by dres. Wordpress gathers the posts from the posts table, then gathers the post meta from the postmeta table. The post meta table is where the json is stored. It is really a simple algorithm, it's just the syntax that is screwing with me.
SELECT SQL_CALC_FOUND_ROWS {$wpdb->posts}.ID
FROM {$wpdb->posts} INNER JOIN {$wpdb->postmeta}
MID(CAST({$wpdb->postmeta}.meta_value AS CHAR),
POSITION(';s:6:\"weight' IN CAST({$wpdb->postmeta}.meta_value AS CHAR) ),10 ) AS dres
ON ({$wpdb->posts}.ID = {$wpdb->postmeta}.post_id)
WHERE 1=1
AND {$wpdb->posts}.post_type = 'dog'
AND ({$wpdb->posts}.post_status = 'publish')
AND {$wpdb->postmeta}.meta_key = '_meta_general'
AND POSITION(';s:6:"weight' IN CAST({$wpdb->postmeta}.meta_value AS CHAR)) > 0
GROUP BY {$wpdb->posts}.ID ORDER BY dres ASC LIMIT 0, 10
You can't use column aliases in your WHERE clause -- what's more, in some cases, those expressions with always evaluate to TRUE, so I don't see why there are there at all.
Perhaps you mean:
SELECT SQL_CALC_FOUND_ROWS
_posts.ID
,MID(
CAST(_postmeta.meta_value AS CHAR),
POSITION(';s:6:\"weight' IN CAST(_postmeta.meta_value AS CHAR) ),
10
) AS dres
FROM _posts
INNER JOIN _postmeta ON (_posts.ID = _postmeta.post_id)
WHERE 1=1
AND _posts.post_type = 'dog' AND _posts.post_status = 'publish'
AND _postmeta.meta_key = '_meta_general'
AND POSITION(';s:6:\"weight' IN CAST(_postmeta.meta_value AS CHAR)) > 0
GROUP BY dres ORDER BY _postmeta.meta_value ASC LIMIT 0, 10