I have a couple of tables, one with source data which I'll call SourceData and another which defines overridden values for a given user if they exist called OverriddenSourceData.
The basic table format looks something this like:
SourceData
| source_id | payload |
--------------------------------
| 1 | 'some json' |
| 2 | 'some more json' |
--------------------------------
OverriddenSourceData
| id | source_id | user_id | overrides
| 1 | 2 | 4 | 'a change' |
------------------------------------------
For a given user, I'd like to return all the Source data rows with the overrides column included. If the user has overridden the source then the column is populated, else it is null.
I started by executing a left join and then including a condition for checking the user like so:
SELECT A.source_id, A.payload, B.overrides from SourceData A
LEFT JOIN OverriddenSourceData B
ON A.source_id = B.source_id
WHERE user_id = 4
but then source rows that weren't overridden wouldn't be included ( it was acting like an inner join) (e.g source id 1)
I then relaxed the query and used a strict left join on source_id.
SELECT A.source_id, A.payload, B.overrides from SourceData A
LEFT JOIN OverriddenSourceData B
ON A.source_id = B.source_id
# WHERE user_id = 4
This can return more data than I need though (e.g other users who have overridden the same source data) and then I have to filter programatically.
It seems like I should be able to craft a query that does this all the DB level and gives me what I need. Any help?
You should add your condition on LEFT JOIN clause, if you use WHERE, mysql will do it with INNER JOIN, so try this;)
SELECT A.source_id, A.payload, B.overrides from SourceData A
LEFT JOIN OverriddenSourceData B
ON A.source_id = B.source_id
AND B.user_id = 4
Related
Actually, there are total 4 tables invoked in this mapping: Market,Cost, A, B,
Read_sourceTB_B-----FIL1------->---------JNR4 \
| | |
| Read_sourceTB_Market--\ | |
| Read_sourceTB_Cost------JNR1--\ | |
| Read_sourceTB_A-----------------JNR2 JNR5--->EXP... -->TGT
| | | |
| | | |
| | | |
---------------------FIL2->---------JNR3 /
SQ_TABLEB --FIL1-> -- JNR1 \
| | |
| SQ_TABLEA --| JNR3-->EXP.... -->TGT
| | |
|--FIL2-> -- JNR2 /
**First **joinning condition
A LEFT JOIN B
ON A.MEMBERSHIPID = B.MEMBERSHIPID
Where B.System_Code='University'
IF <First joinning condition> failed, then execute
**Second **joinning condition
A LEFT JOIN B ON
A.address = B.address and A.phonenumber = B.phonenumber
Where B.System_Code='Policy'
Which transformation should I use? I don't know how to use Informatica, my version is Informatica Developer 10.5, please help me.Thanks!
I only know how to
A left join B on `condition` `System_Code='University'`
left join B on `condition` `System_Code='Policy'`
but I don't know how to make a decision for
if A join B System_Code='University'failed,
then A join B System_Code='Policy'
You need to join A with B (twice) based on two different condition and then join them back to one single pipeline for a decision/if-else condition.
Also please note, all your left joins are actually inner join because you are using B.xxx='something' condition in the where clause.
So, considering above problem -
After source qualified of B, add two filters FIL1(system_Code='University') and FIL2(System_Code='Policy') in parallel.
Then use JNR1 to join A and B(FIL1) using JOINER on A.MEMBERSHIPID = B_F1.MEMBERSHIPID. Use A as detail table and use 'inner join'.
Then join A and B(FIL2) using JOINER(JNR2) on A.address = B_F2.address and A.phonenumber = B_F2.phonenumber. Use A as detail table and use 'inner join'.
Then join above two pipelines into one single pipeline using another Joiner(JNR3). It should be normal join and join should be primary key from table A. Get all required columns.
(EXP)Then use an expression transformation. Use logic similar to below.
out_col1 = IIF( isnull(col_tableB_F1_jnr1),col_tableB_F2_jnr2, col_tableB_F1_jnr1)
Whole mapping should look like this -
SQ_TABLEB --FIL1-> -- JNR1 \
| | |
| SQ_TABLEA --| JNR3-->EXP.... -->TGT
| | |
|--FIL2-> -- JNR2 /
But i think your requirement may be like this -
A LEFT JOIN B
ON A.MEMBERSHIPID = B.MEMBERSHIPID AND B.System_Code='University'
if yes, then change the inner join to master outer join in the JNR1 and JNR2.
I have a table which list available items, when user click on any item it will insert in added_items table. Now my problem is I want to use join to select all items that any user has not added. My current query doesn't show items if one user has added it.
items
name | type | id | user
-------|------|----|------------------
JAVA | A | 1 | SYSTEM
PHP | A | 2 | SYSTEM
HTML | B | 3 | USER1
added_items
item_id | user
----------|--------------
1 | peter
My query
SELECT it.*
FROM items it
LEFT JOIN added_items ait
ON ait.user = it.user
#on ait.item_id = it.id
WHERE it.type = "A"
AND ait.user IS NULL
The second query I tried
SELECT it.*
FROM items it
LEFT JOIN added_items ait
ON ait.item_id = it.id
WHERE it.type = "a"
AND ait.user != "peter"
Expected result
when current user is peter I want to retrieve only PHP as peter has added JAVA.
But if current user isn't on added_items the retrieve all record.
Add fiddle http://sqlfiddle.com/#!9/3761e40
SELECT *
FROM items
WHERE NOT EXISTS ( SELECT NULL
FROM added_items
WHERE items.id = added_items.item_id
-- AND added_items.user = "peter"
)
-- AND items.type = 'A'
fiddle
You can try:
SELECT it.*
FROM items it
LEFT JOIN added_items ait
ON ait.item_id = it.id
WHERE ait.item_id IS NULL
I am trying to avoid passing two separate MySQL (version 5.6.37) queries, and using transactions. I think this can be done in a single query, but I need to know where I'm going wrong.
If I use this query:
SELECT titles.t_id,title,cover,pageData.pageNum
FROM titles
JOIN biblio ON titles.t_id = biblio
JOIN pageData ON biblio.t_id = pageData.t_id
WHERE titles.t_id = '1';
It successfully returns a result with three columns of redundant data, and only one column of new data (p_id):
t_id | title | cover | pageNum
1 | The Art of the Deal | 32.jpg | 1
1 | The Art of the Deal | 32.jpg | 2
1 | The Art of the Deal | 32.jpg | 3
1 | The Art of the Deal | 32.jpg | 4
1 | The Art of the Deal | 32.jpg | 5
I think there is a way to modify the query so that the new data in the pageNum column is flattened into a single result (i.e. converted from integer values to a delimited string), like this:
t_id | title | cover | p_id
1 | The Art of the Deal | 32.jpg | 1,2,3,4,5
I have been experimenting with a sub-SELECT within the SELECT, but I have consistent syntax errors. Is there a way to combine these two queries below to get the above result?
SELECT titles.t_id,title,cover
FROM titles
JOIN biblio ON titles.t_id = biblio
WHERE titles.t_id = '1';
and
SELECT pageData.pageNum FROM pageData WHERE pageData.t_id = '1'
You can use GROUP_CONCAT in combination with GROUP BY for that.
SET SESSION group_concat_max_len = ##max_allowed_packet
SELECT
titles.t_id
, title,cover
, GROUP_CONCAT(pageData.pageNum) AS p_id
FROM titles
JOIN biblio ON titles.t_id = biblio
JOIN pageData ON biblio.t_id = pageData.t_id
WHERE titles.t_id = '1'
GROUP BY
t_id
, title
, cover
Use the GROUP_CONCAT function. Also assuming you meant JOIN biblio ON titles.t_id = biblio.t_id
SELECT t.t_id, title, cover, GROUP_CONCAT(pageData.pageNum) AS pageNum
FROM titles t
JOIN biblio b ON t.t_id = b.t_id
JOIN pageData p ON b.t_id = p.t_id
WHERE t.t_id = '1'
GROUP BY t.t_id, title, cover
The result you need can be easily accomplished using the MySQL function GROUP_CONCAT().
In order to produce a valid SQL query and get the results you expect, you also need to add a GROUP BY clause to the query and put in it all the other columns that appear in the SELECT clause:
SELECT titles.t_id, title, cover, GROUP_CONCAT(pageData.pageNum) AS p_id
FROM titles
JOIN biblio ON titles.t_id = biblio
JOIN pageData ON biblio.t_id = pageData.t_id
WHERE titles.t_id = '1'
GROUP BY titles.t_id, title, cover
I have two tables reports & viewedids
the first one stores data and the second one stores user IDs that viewed data:
viewedids:
+-------+------+
| uid | rid |
+-------+------+
| 2 | 5 |
+-------+------+
each (uid,rid) means the uid has viewd rid
I want to select * from reports table and add view state (0 or 1) for current user to it. (A JOIN statement)
How can I do this?
You can use a LEFT JOIN:
SELECT reports.*, viewedids.uid IS NOT NULL as view_state
FROM
reports LEFT JOIN viewedids
ON reports.id = viewedids.rid
AND viewedids.uid = #current_user
This will return all reports, and will try to join reports table with viewedids ON reports.id = viewedids.rid AND viewedids.uid = #current_user. If the join succedes, viewedids.uid will be not null, and viewedids.uid IS NOT NULL will be evaluated to 1. It will be evaluated 0 otherwise.
Please see fiddle here.
Ok I have a few tables tables. I am only showing relevant fields:
items:
----------------------------------------------------------------
name | owner_id | location_id | cab_id | description |
----------------------------------------------------------------
itm_A | 11 | 23 | 100 | Blah |
----------------------------------------------------------------
.
.
.
users:
-------------------------
id | name |
-------------------------
11 | John |
-------------------------
.
.
.
locations
-------------------------
id | name |
-------------------------
23 | Seattle |
-------------------------
.
.
.
cabs
id | location_id | name
-----------------------------------
100 | 23 | Cool |
-----------------------------------
101 | 24 | Cool |
-----------------------------------
102 | 24 |thecab |
-----------------------------------
I am trying to SELECT all items (and their owner info) that are from Seattle OR Denver, but if they are in Seattle they can only be in the cab NAMED Cool and if they are in Denver they can only be in the cab named 'thecab' (not Denver AND cool).
This query doesn't work but I hope it explains what I am trying to accomplish:
SELECT DISTINCT
`item`.`name`,
`item`.`owner_id`,
`item`.`description`,
`user`.`name`,
IF(`loc`.`name` = 'Seattle' AND `cab`.`name` = 'Cool',1,0) AS `cab_test_1`,
IF(`loc`.`name` = 'Denver' AND `cab`.`name` = 'thecab',1,0) AS `cab_test_2`,
FROM `items` AS `item`
LEFT JOIN `users` AS `user` ON `item`.`owner_id` = `user`.`id`
LEFT JOIN `locations` AS `loc` ON `item`.`location_id` = `loc`.`location_id`
LEFT JOIN `cabs` AS `cab` ON `item`.`cab_id` = `cabs`.`id`
WHERE (`loc`.`name` IN ("Seattle","Denver")) AND `cab_test_1` = 1 AND `cab_test_2` = 1
I'd rather get rid of the IFs is possible. It seems inefficent, looks clunky, and is not scalable if I have a lot of location\name pairs
Try this:
SELECT DISTINCT
item.name,
item.owner_id,
item.description,
user.name
FROM items AS item
LEFT JOIN users AS user ON item.owner_id = user.id
LEFT JOIN locations AS loc ON item.location_id = loc.id
LEFT JOIN cabs AS cab ON item.cab_id = cabs.id
WHERE ((loc.name = 'Seattle' AND cab.name = 'Cool')
OR (loc.name = 'Denver' AND cab.name = 'thecab'))
My first thought is to store the pairs of locations and cab names in a separate table. Well not quite a table, but a derived table generated by a subquery.
You still have the problem of pivoting the test results into separate columns. The code can be simplified by making use of mysql boolean expressions, which get rid of the need for a case or if.
So, the approach is to use the same joins you have (although left join is not needed because the comparison on cab.name turns them in to inner joins). Then add a table of the pairs you are looking for, along with the "test name" for the pair. The final step is an explicit group by and a check whether conditions are met for each test:
SELECT i.`name`, i.`owner_id`, i.`description`, u.`name`,
max(pairs.test_name = 'test_1') as cab_test_1,
max(pairs.test_name = 'test_2') as cab_test_2
FROM `items` i LEFT JOIN
`users` u
ON i.`owner_id` = u.`id` LEFT JOIN
`locations` l`
ON i.`location_id` = l.`location_id` left join
`cabs` c
ON i.`cab_id` = c.`id` join
(select 'test_1' as testname, 'Seattle' as loc, 'cool' as cabname union all
select 'test_2', 'Denver', 'thecab'
) pairs
on l.name = pairs.name and
l.cabname = c.name
group by i.`name`, i.`owner_id`, i.`description`, u.`name`;
To add in additional pairs, add them into the pairs table along, and add an appropriate line in the select for the test flag.