How to join table A to B to find all the entries in A whose intervals contain entries in B? - sql

I am comparing two tables A and B of log entry intervals, i.e. each record in a table is the first log entry and then another, for a given user, like this:
+--------+----------+--------+-----------+--------+
| userID | date1 | logID1 | date2 | logID2 |
+--------+----------+--------+-----------+--------+
| 235 | 1/3/2013 | 45 | 1/7/2013 | 48 |
| 235 | 4/6/2013 | 64 | 4/12/2013 | 73 |
| 462 | 1/4/2013 | 40 | 1/16/2013 | 50 |
+--------+----------+--------+-----------+--------+
I want to build a join query that links every record in A to all the records in B based on userID, where A contains B in either dates:
a.date1<=b.date1, a.date2>=b.date2
or IDs:
a.logID1<=b.logID1, a.logID2>=b.logID2
I want to return all records in A, regardless of whether or not there is a contained interval in B.
At first glance it seems like this would work:
select * from a
left join b
on
a.userID=b.userID
where
(a.date1<=b.date1 or a.logID1<=b.logID1)
and
(a.date2>=b.date2 or a.logID2>=b.logID2)
or
b.userID is null
But the problem is that if there is a record in A that has a matching userID in B but the A record does not contain the B record, the join will occur but the record will be filtered out by the WHERE condition, so the A record will not appear in the results.
If I try to resolve this by moving the WHERE conditions to the JOIN clause as follows:
select * from a
left join b
on
a.userID=b.userID
and
(a.date1<=b.date1 or a.logID1<=b.logID1)
and
(a.date2>=b.date2 or a.logID2>=b.logID2)
then I get this error message:
JOIN expression not supported.
I assume this means Access can't have nested OR conditions in the JOIN criteria.
What can I do to return a list of A, joined to their contained B where applicable?

If you want all records in a, then put the condition in the on clause. where has strange effects. So try:
select *
from a left join
b
on a.userID = b.userID and
(a.date1<=b.date1 or a.logID1<=b.logID1)
(a.date2>=b.date2 or a.logID2>=b.logID2);

Related

Left Join with Distinct Right table returns more rows in SQL Server

I have two tables, one is my Main table and one is Mapping table. The simplified tables look like this :
Main :
VALUE | CUSTNAME
123 | ADELE
323 | GORTH
242 | GORTH
345 | VIX
...
Mapping :
ISSUER | CATEGORY
ADELE | A
GORTH | B
DENN | B
VIX | C
...
What I want to do is add a CATEGORY column to my Main table, so I to use a left join, but somehow it returns more rows than I originally have. And I can't check it one by one because it has around 30000 records. The increase it self is miniscule, 40 records, but it still a difference and it shows.
Things to note and things I already tried :
Main table can hold the same CUSTNAME while Mapping table is distinct, making it many-to-one relation.
Mapping table holds duplicate records, so I tried to select distinct it first before joining it
I already checked the NULL to see if the Mapping table miss anything, but it doesn't seems to be the case
I use both inner join and left join but it return the same result
So what did I do wrong here and how can I fix it?
My query :
SELECT A.*, B.CATEGORY AS CATEGORY
FROM Main A
LEFT JOIN
(SELECT DISTINCT * FROM Mapping) B ON A.CUSTNAME = B.Issuer
My output right now :
VALUE | CUSTNAME | CATEGORY
123 | ADELE | A
323 | GORTH | B
242 | GORTH | B
345 | VIX | C
... with extra 40 records
My expected output :
VALUE | CUSTNAME | CATEGORY
123 | ADELE | A
323 | GORTH | B
242 | GORTH | B
345 | VIX | C
... without extra 40 records
You can do it as follows if you are looking to eliminate duplicates Mapping.Issuer ONLY.
SELECT A.*, B.CATEGORY AS CATEGORY
FROM Main A
LEFT JOIN
(SELECT Issuer, MAX(CATEGORY) AS CATEGORY FROM Mapping group by Issuer) B ON A.CUSTNAME = B.Issuer
Probably you have data on Mapping table like :
insert into Mapping values
('ADELE','A'),
('GORTH','B'),
('DENN','B'),
('VIX','C'),
('VIX','D');
That means ('VIX','C'), ('VIX','D') are not duplicates
demo here
This:
SELECT DISTINCT * FROM Mapping
won't prevent duplicates. Distinct * means that the tuple(combination) of ALL columns will be considered as unique; However, if there are two rows with same Issuer but a different value in any of the other columns, it will still return multiple rows. Like this:
Issuer | ManufactureId
5623 894
5623 895
This, in turn, will make one row from A turn into multiple from the left join.

Comparing aggregated columns to non aggregated columns to remove matches

I have two separate tables from two different databases that are performing a matching check.
If the values match I want them out of the result set. The first table (A) has multiple entries that contain the same symbol matches for the matching columns in the second table (B).
The entries in table B, if added up will ideally equal the value of one of the matching rows of A.
The tables look like below when queried separately.
Underneath the tables is what my query currently looks like. I thought if I group the columns by the symbols I could use the SUM of B to add up to the value of A which would get rid of the entries. However, I think because I am summing from B and not from A, then the A doesn't count as an aggregated column so must be included in the group by and doesn't allow for the summing to work in the way I'm wanting it to calculate.
How would I be able to run this query so the values in B are all summed up. Then, if matching to the symbol/value from any of the entries in A, don't get included in the result set?
Table A
| Symbol | Value |
|--------|-------|
| A | 1000 |
| A | 1000 |
| B | 1440 |
| B | 1440 |
| C | 1235 |
Table B
| Symbol | Value |
|--------|-------|
| A | 750 |
| A | 250 |
| B | 24 |
| B | 1416|
| C | 1874|
SELECT DBA.A, DBB.B
FROM DatabaseA DBA
INNER JOIN DatabaseB DBB on DBA.Symbol = DBB.Symbol
and DBA.Value != DBB.Value
group by DBA.Symbol, DBB.Symbol, DBB.Value
having SUM(DBB.Value) != DBA.Value
order by Symbol, Value
Edited to add ideal results
Table C
| SymbolB| ValueB| SymbolA | ValueA |
|--------|-------|---------|--------|
| C | 1874 | C | 1235 |
Wherever B adds up to A remove both. If they don't add, leave number inside result set
I will use CTE and use this common table expression (CTE) to search in Table A. Then join table A and table B on symbol.
WITH tDBB as (
SELECT DBB.Symbol, SUM(DBB.Value) as total
FROM tableB as DBB
GROUP BY DBB.Symbol
)
SELECT distinct DBB.Symbol as SymbolB, DBB.Value as ValueB, DBA.Symbol as SymbolA, DBA.Value as ValueA
FROM tableA as DBA
INNER JOIN tableB as DBB on DBA.Symbol = DBB.Symbol
WHERE DBA.Symbol in (Select Symbol from tDBB)
AND NOT DBA.Value in (Select total from tDBB)
Result:
|symbolB |valueB |SymbolA |ValueA |
|--------|-------|--------|-------|
| C | 1874 | C | 1235 |
with t3 as (
select symbol
,sum(value) as value
from t2
group by symbol
)
select *
from t3 join t on t.symbol = t3.symbol and t.value != t3.value
symbol
value
Symbol
Value
C
1874
C
1235
Fiddle

INNER JOIN Need to use column value twice in results

I've put in the requisite 2+ hours of digging and not getting an answer.
I'd like to merge 3 SQL tables, where Table A and B share a column in common, and Table B and C share a column in common--Tables A and C do not.
For example:
Table A - entity_list
entity_id | entity_name | Other, irrelevant columns
Example:
1 | Microsoft |
2 | Google |
Table B - transaction_history
transaction_id | purchasing_entity | supplying_entity | other, irrelevant columns
Example:
1 | 2 | 1
Table C - transaction_details
transactional_id | amount_of_purchase | Other, irrelevant columns
1 | 5000000 |
Using INNER JOIN, I've been able to get a result where I can link entity_name to either purchasing_entity or supplying_entity. And then, in the results, rather than seeing the entity_id, I get the entity name. But I want to substitute the entity name for both purchasing and supplying entity.
My ideal results would look like this:
1 [transaction ID] | Microsoft | Google | 5000000
The closes I've come is:
1 [transaction ID] | Microsoft | 2 [Supplying Entity] | 5000000
To get there, I've done:
SELECT transaction_history.transaction_id,
entity_list.entity_name,
transaction_history.supplying_entity,
transaction_details.amount_of_purchase
FROM transaction.history
INNER JOIN entity_list
ON transaction_history.purchasing_entity=entity_list.entity.id
INNER JOIN
ON transaction_history.transaction_id=transaction_details.transaction_id
I can't get entity_name to feed to both purchasing_entity and supplying_entity.
Here is the query:
SELECT h.transaction_id, h.purchasing_entity, purchaser.entity_name, h.supplying_entity, supplier.entity_name, d.amount_of_purchase
FROM transaction_history h
INNER JOIN transaction_details d
ON h.transaction_id = d.transaction_id
INNER JOIN entity_list purchaser
ON h.purchasing_entity = purchaser.entity_id
INNER JOIN entity_list supplier
ON h.supplying_entity = supplier.entity_id

GROUP BY shows the same group more than once when using CASE

I'm having an issue with a CASE Statement in T-SQL
Here is the query:
Select
CASE WHEN cri.ChartRetrievalMethodID IS NULL THEN wfseg.SiteEventGroupID
ELSE cri.ChartRetrievalMethodID END as Type,
count(distinct c.chartid) TotalCharts
From Sites s LEFT JOIN Charts c ON s.SiteID=c.SiteID
LEFT JOIN ChartRetrievalInformation cri ON c.ChartID=cri.ChartID
LEFT JOIN WFSiteEvents wfse ON wfse.SiteID=s.siteid
LEFT JOIN WFSiteEventTypes wfset ON wfset.EventTypeID=wfse.EventTypeID
LEFT JOIN WFSiteEventGroups wfseg ON wfset.SiteEventGroupID=wfseg.SiteEventGroupID
Where
wfse.EventStatusID in (1,2)
and s.ProjectID=110
group by
cri.ChartRetrievalMethodID, wfseg.SiteEventGroupID
I'm getting a lot of multiple rows instead of them combining into one - example:
+------+--------------+
| Type | Total Charts |
+------+--------------+
| 3 | 28 |
| 3 | 3 |
+------+--------------+
Ideally I would like these two rows mashed together to be just one:
+------+--------------+
| Type | Total Charts |
+------+--------------+
| 3 | 31 |
+------+--------------+
I'm sure there is nothing I'm writing incorrectly but I can't seem to see what it is.
If you include the fields cri.ChartRetrievalMethodID, wfseg.SiteEventGroupID in the column list for your select statement, it will become clear to you why these are shown in multiple rows with that grouping.
What you want to do is group by the value you're calling Type. In another DBMS this would be as simple as GROUP BY Type, but in SQL Server you must repeat the full expression in the GROUP BY clause.

join on three tables? Error in phpMyAdmin

I'm trying to use a join on three tables query I found in another post (post #5 here). When I try to use this in the SQL tab of one of my tables in phpMyAdmin, it gives me an error:
#1066 - Not unique table/alias: 'm'
The exact query I'm trying to use is:
select r.*,m.SkuAbbr, v.VoucherNbr from arrc_RedeemActivity r, arrc_Merchant m, arrc_Voucher v
LEFT OUTER JOIN arrc_Merchant m ON (r.MerchantID = m.MerchantID)
LEFT OUTER JOIN arrc_Voucher v ON (r.VoucherID = v.VoucherID)
I'm not entirely certain it will do what I need it to do or that I'm using the right kind of join (my grasp of SQL is pretty limited at this point), but I was hoping to at least see what it produced.
(What I'm trying to do, if anyone cares to assist, is get all columns from arrc_RedeemActivity, plus SkuAbbr from arrc_Merchant where the merchant IDs match in those two tables, plus VoucherNbr from arrc_Voucher where VoucherIDs match in those two tables.)
Edited to add table samples
Table arrc_RedeemActivity
RedeemID | VoucherID | MerchantID | RedeemAmt
----------------------------------------------
1 | 2 | 3 | 25
2 | 6 | 5 | 50
Table arrc_Merchant
MerchantID | SkuAbbr
---------------------
3 | abc
5 | def
Table arrc_Voucher
VoucherID | VoucherNbr
-----------------------
2 | 12345
6 | 23456
So ideally, what I'd like to get back would be:
RedeemID | VoucherID | MerchantID | RedeemAmt | SkuAbbr | VoucherNbr
-----------------------------------------------------------------------
1 | 2 | 3 | 25 | abc | 12345
2 | 2 | 5 | 50 | def | 23456
The problem was you had duplicate table references - which would work, except for that this included table aliasing.
If you want to only see rows where there are supporting records in both tables, use:
SELECT r.*,
m.SkuAbbr,
v.VoucherNbr
FROM arrc_RedeemActivity r
JOIN arrc_Merchant m ON m.merchantid = r.merchantid
JOIN arrc_Voucher v ON v.voucherid = r.voucherid
This will show NULL for the m and v references that don't have a match based on the JOIN criteria:
SELECT r.*,
m.SkuAbbr,
v.VoucherNbr
FROM arrc_RedeemActivity r
LEFT JOIN arrc_Merchant m ON m.merchantid = r.merchantid
LEFT JOIN arrc_Voucher v ON v.voucherid = r.voucherid