Matching values in two tables query (SQL and ColdFusion) - sql

I have a query that has a list of base values and a list of language values. Each value has a key that matches to the other. The base values are stored in one table and the language values in another. My problem is that I need to get all matching base values removed from the QUERY except for one. Then, I export that query into an Excel spreadsheet (I can do this portion fine) and allow the user to edit the language values.
When the user edits and/or inserts new language values, I need to update the database except now writing over any matching values in the database (like those that were removed the first time).
In simplicity, the client pays for translations and if I can generate a sheet that has fewer translations needed (like phrases that reappear often) then they can save money, hence the project to begin with. I realize the downside is that it is not a true linked list, where all matching values all belong to one row in the language table (which would have been easy). Instead, there are multiple values that are identical that need to be updated as described above.
Yeah, I'm confused on it which is why it might seem a little vague. Here's a sample:
Table 1
Item Description1
Item Description2
Item Description3
Item Description2
Item Description2
Item Description4
Item Description5
Item Description6
Item Description3
Table 2
Item Desc in other Language1
Item Desc in other Language2
Item Desc in other Language3 (blank)
Item Desc in other Language3
Item Desc in other Language4
Item Desc in other Language5
*blank*
Desired Result (when queried)
Table 1
Item Description1
Item Description2
Item Description3
Item Description4
Item Description5
Item Description6
Table 2
Item Desc in other Language1
Item Desc in other Language2
Item Desc in other Language3 (filled by matching row in Table 2)
Item Desc in other Language4
Item Desc in other Language5
Item Desc in other Language6 (blank, returned as empty string)
The user makes their modifications, including inserting data into blank rows (like row 6 for the language) then reuploads:
Table 1
Item Description1
Item Description2
Item Description3
Item Description2
Item Description2
Item Description4
Item Description5
Item Description6
Item Description3
Table 2
Item Desc in other Language1
Item Desc in other Language2
Item Desc in other Language3 (now matches row below)
Item Desc in other Language3
Item Desc in other Language4
Item Desc in other Language5
Item Desc in other Language6 (new value entered by user)
There is also a resource key that matches each "Item Description" to a single "Item Desc in other Language". The only time they are ever going to see each other is during this translation process, all other times the values may be different, so the resource keys can't simply be changed to all point at one translation permanently.
I should also add, there should be no alteration of the structure of the tables or removing rows of the table.
Ok, here's an updated revisal of what I would LIKE the query to do, but obviously does not do since I actually need the values of the joined table:
SELECT pe.prodtree_element_name_l, rs.resource_value, pe.prodtree_element_name_l_rk
FROM prodtree_element pe
LEFT JOIN resource_shortstrings rs
ON pe.prodtree_element_name_l_rk = rs.resource_key
WHERE rs.language_id = '5'
AND pe.prodtree_element_name_l <> ''
GROUP BY pe.prodtree_element_name_l

Hrm, still not real clear on what the issue truly is, but let me give it a go.
Tables:
BASE_VALUES
------------------
BASE_VALUE_RK
BASE_VALUE_NAME
RESOURCE_VALUES (these are the translations, I'm guessing)
-----------------------
RESOURCE_KEY
RESOURCE_LANGUAGE_ID
RESOURCE_VALUE
You want to retrieve one base value, and all corresponding translation values that match that base value, export them to excel, and then re-load them via an update (I think).
SQL to SELECT out data:
SELECT bv.BASE_VALUE_RK, rv.RESOURVE_VALUE
FROM BASE_VALUE bv, RESOURCE_VALUE rv
WHERE bv.BASE_VALUE_RK = rv.RESOURCE_KEY
AND rv.resource_language_id = '5'
ORDER BY 1;
That'll give you:
1234 Foo
1235 Bar
1236 Baz
Export that to excel, and get it back with updates:
1234 Goo
1235 Car
1236 Spaz
You can then say:
UPDATE RESOURCE_VALUES
SET RESOURCE_VALUE = value_from_spreadsheet
WHERE RESOURCE_KEY = key_from_spreadsheet
I may be way off base on this guy, so let me know and, if you can provide a little more detail, I may be able to score closer to the mark.
Cheers!

If you need to remove all matches except for one, why not delete all the matching ... matches ... we need better terms ... and then insert the correct one. EG, if you need to update the matches between items 12 and 13 in the base pair table, do something like
delete from matchtable where (id1 = 12 and id2 = 13) or (id1 = 13 and id2 = 13);
insert into matchtable (id1, id2) values (12, 13);
I may be oversimplifying, but your description seems vague in places.

Hey thanks for that update!
Looking at that and adding it into a previous post I finally came up with this:
<cfquery name="getRows" datasource="XXXX">
SELECT pe.prodtree_element_name_l, MAX(rs.resource_value) AS resource_value
FROM prodtree_element pe
LEFT JOIN resource_shortstrings rs
ON pe.prodtree_element_name_l_rk = rs.resource_key
WHERE rs.language_id = '5'
AND pe.prodtree_element_name_l <> ''
GROUP BY prodtree_element_name_l
</cfquery>
I realized I didn't need a specific resource_value, just any that was in there. I also realized I didn't need the resource key at all outside of the query. The update will be updating ALL the matching base values regardless, so I didn't really need the resource key after all, which allowed me to use the GROUP BY.
Took a while, sorry for the poor explanation, but this is it! :) Thanks for all the help.

Related

SQL group related rows in a list

I'm a bit stuck with this...
I have items table:
id | name
1 | item 1
2 | item 2
3 | item 3
4 | item 4
and related items table:
id | item_id | related_item_id
2 | 1 | 2
3 | 1 | 4
so this means that item 1 is related to items 2 and 4.
Now I'm trying to display these in a list where related items follow always the main item they are related to:
item 1
item 2
item 4
item 3
Then I can visually show that these items 2 and 4 are related to item one and draw something like:
item 1
-- item 2
-- item 4
item 3
To be honest, haven't got any ideas myself. I quess I could query for items which are not related to any other item and get a list of "parent items" and then query relations separately in a script loop. This is not definately the sexiest solution...
I am assuming that this question is about ordering the items list, without duplicates. That is, a given item does not have more than one parent (which I ask in a comment).
If so, you can do this with a left outer join and cleverness in the order by.
select coalesce(r.related_item_id, i.id) as item_id
from items i left join
related r
on i.id = r.related_item_id
order by coalesce(r.item_id, i.id),
(r.related_item_id is null) desc;
The left outer join identifies parents because they will not have any rows that match. If so, the coalesce() finds them and uses the item id.
In my opinion , rather than implementing this logic in a query , you should move it to your actual code.
assuming that item_ids are sequential, you can find the largest number of item_id, then in a loop
you can find related_item_id to each item_id and make a convenient data structure out of it.
This functionality comes under the category of hierarchical queries. In Oracle its handled by connect by clause not sure about mysql. But you can search "hierarchical queries mysql" to get the answer.

Multi-Row Per Record SQL Statement

I'm not sure this is possible but my manager wants me to do it...
Using the below picture as a reference, is it possible to retrieve a group of records, where each record has 2 rows of columns?
So columns: Number, Incident Number, Vendor Number, Customer Name, Customer Location, Status, Opened and Updated would be part of the first row and column: Work Notes would be a new row that spans the width of the report. Each record would have two rows. Is this possible with a GROUP BY statement?
Record 1
Row 1 = Number, Incident Number, Vendor Number, Customer Name, Customer Location, Status, Opened and Updated
Row 2 = Work Notes
Record 2
Row 1 = Number, Incident Number, Vendor Number, Customer Name, Customer Location, Status, Opened and Updated
Row 2 = Work Notes
Record n
...
I don't think that possible with the built in report engine. You'll need to export the data and format it using something else.
You could have something similar to what you want on short description (list report, group by short description), but you can't group by work notes so that's out.
One thing to note is that the work_notes field is not actually a field on the table, the work_notes field is of type journal_input, which means it's really just a gateway to the actual underlying data model. "Modifying" work_notes actually just inserts into sys_journal_field.
sys_journal_field is the table which stores the work notes you're looking for. Given a sys_id of an incident record, this URL will give you all journal field entries for that particular record:
/sys_journal_field_list.do?sysparm_query=name=task^element_id=<YOUR_SYS_ID>
You will notice this includes ALL journal fields (comments + work_notes + anything else), so if you just wanted work notes, you could simply add a query against element thusly:
/sys_journal_field_list.do?sysparm_query=name=task^element=work_notes^element_id=<YOUR_SYS_ID>
What this means for you!
While you can't separate a physical row into multiple logical rows in the UI, in the case of journal fields you can join your target table against the sys_journal_field table using a Database View. This deviates from your goal in that you wouldn't get a single row for all work notes, but rather an additional row for each matched work note.
Given an incident INC123 with 3 work notes, your report against the Database View would look kind of like this:
Row 1: INT123 | markmilly | This is a test incident |
Row 2: INT123 | | | Work note #1
Row 3: INT123 | | | Work note #2
Row 4: INT123 | | | Work note #3

Fill a drop-down list parameter with specific available values

I have an SSRS report that creates report from a SQL table:
id type name
1 fruit wilk
2 fruit scot
3 paper jon
4 pen brad
5 tape lin
6 water james
The report has two data sets: one feeds query for report, and the other feeds data to parameter. So in the report the multi-value parameter gets its values from dataset2.
-- dataset1::
select ID, TYPE, name from table1 where type in (#types)
-- dataset2::
select TYPE from table1
The report is generated based on type selected from dropdown list (which is a multi select list).
For example if we select "fruit" the report displays:
wilk, scot
If we select "water":
james
Now the thing is that I need to create a name for all the values "TAPE", "pen", and "paper", say the name "STATIONARY", such that the dropdown list should show only:
fruit, stationary, water
And when I select "STATIONARY" from thedropdown list the report should display:
jon, brad, lin (all 3 have some form of stationary, i.e paper, pen, tape)
And when I select type as "STATIONARY" and "water" it should display:
jon, brad, lin, james
Just from the hip here.
Consider adding a category field to your table. So for your fruit and water you could have a category called "Food", and for your pen, paper, and tape the category would be called "stationary".
Add another dataset to your report called "category".
SELECT Category FROM table1
Add another parameter that is a multiple selection of your new data set called #Category.
In your main query add:
...AND Category IN (#Category)
EDIT
Keep in mind this advice completely ignores normalization in your database. I understand that is not the intent of your question but it is something you should always consider. If it were me I would even add a category table. Then with the "table1" as you call it I would add a foriegn key pointing at an ID in the category table. You can even see this issue with your type column. Notice how fruit is used more than once.
I'd create another couple of tables for this called Item and ItemType.
ItemType has two fields: ItemTypeId (the auto-incrementing primary key) and Name. ItemType will have values like:
ItemTypeId Name
1 Food
2 Stationery
Item has three fields: ItemId (the auto-incrementing primary key), Name and ItemTypeId (from the ItemType table above). It looks like this:
ItemId Name ItemTypeId
1 Fruit 1
2 Paper 2
3 Pen 2
4 Tape 2
5 Water 1
Add the ItemId field to table1 and remove the type field, so it now looks like:
id ItemId name
1 1 wilk
2 1 scot
3 2 jon
4 3 brad
5 4 lin
6 5 james
We now know the type of the item from the link to the ItemType.
Create two parameters: #ItemTypes and #Items as multi-value.
#ItemTypes populates from the ItemType table:
SELECT ItemTypeId, Name FROM ItemType
ItemTypeId is the Value and Name is the Label.
#Items populates from the Item table but is filtered on the #ItemTypes parameter like so:
SELECT ItemId, Name FROM Item WHERE (ItemTypeId IN #ItemTypes)
ItemId is the Value and Name is the Label.
Now when you select #ItemTypes in the first parameter, the second parameter will only show items of that type.
Okay, back to your query. Your main query now looks like:
SELECT Item.Name AS ItemName, ItemType.Name AS ItemTypeName, table1.Name
FROM table1
INNER JOIN Item ON Item.ItemId = table1.ItemId
INNER JOIN ItemType ON ItemType.ItemTypeId = Item.ItemTypeI
WHERE (ItemType.ItemTypeId IN #ItemTypes)
AND (Item.ItemId IN #Items)
and I think our work here is done.

How to make SQL query that will combine rows of result from one table with rows of another table in specific conditions in SQLite

I have aSQLite3 database with three tables. Sample data looks like this:
Original
id aName code
------------------
1 dog DG
2 cat CT
3 bat BT
4 badger BDGR
... ... ...
Translated
id orgID isTranslated langID aName
----------------------------------------------
1 2 1 3 katze
2 1 1 3 hund
3 3 0 3 (NULL)
4 4 1 3 dachs
... ... ... ... ...
Lang
id Langcode
-----------
1 FR
2 CZ
3 DE
4 RU
... ...
I want to select all data from Original and Translated in way that result would consist of all data in Original table, but aName of rows that got translation would be replaced with aName from Translated table, so then I could apply an ORDER BY clause and sort data in the desired way.
All data and table designs are examples just to show the problem. The schema does contain some elements like an isTranslated column or translation and original names in separate tables. These elements are required by application destination/design.
To be more specific this is an example rowset I would like to produce. It's all the data from table Original modified by data from Translated if translation is available for that certain id from Original.
Desired Result
id aName code isTranslated
---------------------------------
1 hund DG 1
2 katze CT 1
3 bat BT 0
4 dachs BDGR 1
... ... ... ...
This is a typcial application for the CASE expression:
SELECT Original.id,
CASE isTranslated
WHEN 1 THEN Translated.aName
ELSE Original.aName
END AS aName,
code,
isTranslated
FROM Original
JOIN Translated ON Original.id = Translated.orgID
WHERE Translated.langID = (SELECT id FROM Lang WHERE Langcode = 'DE')
If not all records in Original have a corresponding record in Translated, use LEFT JOIN instead.
If untranslated names are guaranteed to be NULL, you can just use IFNULL(Translated.aName, Original.aName) instead.
You should probably list the actual results you want, which would help people help you in the future.
In the current case, I'm guessing you want something along these lines:
SELECT Original.id, Original.code, Translated.aName
FROM Original
JOIN Lang
ON Lang.langCode = 'DE'
JOIN Translated
ON Translated.orgId = Original.id
AND Translated.langId = Lang.id
AND Translated.aName IS NOT NULL;
(Check out my example to see if these are the results you want).
In any case, the table set you've got is heading towards a fairly standard 'translation table' setup. However, there are some basic changes I'd make.
Original
Name the table to something specific, like Animal
Don't include a 'default' translation in the table (you can use a view, if necessary).
'code' is fine, although in the case of animals, genus/species probably ought to be used
Lang
'Lanugage' is often a reserved word in RDBMSs, so the name is fine.
Specifically name which 'language code' you're using (and don't abbreviate column names). There's actually (up to) three different ISO codes possible - just grab them all.
(Also, remember that languages have language-specific names, so language also needs it's own 'translation' table)
Translated
Name the table entity-specific, like AnimalNameTranslated, or somesuch.
isTranslated is unnecessary - you can derive it from the existence of the row - don't add a row if the term isn't translated yet.
Put all 'translations' into the table, including the 'default' one. This means all your terms are in one place, so you don't have to go looking elsewhere.

How to specify row names in MS Access 2007

I have a cross tab query and it pulls only the row name if there is data associated with it in the database. For example, if I have three types of musical instruments:
Guitar
Piano
Drums
Other
My results will show up as:
Guitar 1
Drums 2
It doesn't list Piano because there is no ID associated with Piano in the DB. I know I can specify columns in the properties menu, i.e. "1, 2, 3, 4, 5" will put columns in the DB for each, regardless of whether or not there is data to populate them.
I am looking for a similar solution for rows. Any ideas?
Also, I need NULL values to show up as 0.
Here's the actual SQL (forget the instrument example above)
TRANSFORM Count(Research.Patient_ID) AS CountOfPatient_ID
SELECT
Switch(
[Age]<22,"21 and under",
[Age]>=22 And [AGE]<=24,"Between 22 And 24",
[Age]>=25 And [AGE]<=29,"Between 25 And 29",
[Age]>=30 And [AGE]<=34,"30-34",
[Age]>=35 And [AGE]<=39,"35-39",
[Age]>=40 And [AGE]<=44,"40-44",
[Age]>44,"Over 44"
) AS Age_Range
FROM (Research
INNER JOIN (
SELECT ID, DateDiff("yyyy",DOB,Date()) AS AGE FROM Demographics
) AS Demographics ON Research.Patient_ID=Demographics.ID)
INNER JOIN [Letter Status] ON Research.Patient_ID=[Letter Status].Patient_ID
WHERE ((([Letter Status].Letter_Count)=1))
GROUP BY Demographics.AGE, [Letter Status].Letter_Count
PIVOT Research.Site In (1,2,3,4,5,6,7,8,9,10);
In short, I need all of the rows to show up regardless of whether or not there is a value (for some reason the LEFT JOIN isn't working, so if you can, please use my code to form your answer), and I also need to replace NULL values with 0.
Thanks
I believe this has to do with the way you are joining the instruments table to the IDs table. If you use a left outer join from instruments to IDs, Piano should be included. It would be helpful to see your actual tables and queries though, as your question is kind of vague.
What if you union the select with a hard coded select with one value for each age group.
select 1 as Guitar, 1 as Piano, 1 as Drums, 1 as Other
When you do the transform, each row will have a result that is +1 of the result you want.
foo barTmpCount
-------- ------------
Guitar 2
Piano 1
Drums 3
Other 1
You can then do a
select foo, barTmpCount - 1 as barCount from <query>
and get something like this
foo barCount
-------- ---------
Guitar 1
Piano 0
Drums 2
Other 0