select the master table and relation table where by some column id - sql

I don't know it is possible or not only with sql.
what I want to do is select the master table and relation table where by some column id
product_id | product
-------------------+-------------
21 | Milk
26 | HeadPhone
25 | TV
product_id | custom_id
-------------------+----------
21 | 213
26 | 245
26 | 229
25 | 245
25 | 244
is it possible to find by custom_id,
Below is something likes where custom_id = 245
product_id | product | custom_id
------------+-------------+---------
26 | HeadPhone | 245,229
25 | TV | 245,244

I am not entirely sure I understand the part "something likes where custom_id = 245", but maybe you are looking for something this.
select mt.product_id,
mt.product,
string_agg(rt.custom_id::text, ',' order by rt.custom_id desc) as custom_ids
from master_table mt
join relation_table rt on mt.product_id = rt.product_id
where exists (select *
from relation_table mt2
where mt2.product_id = mt.product_id
and mt2.custom_id = 245)
group by mt.product_id, mt.product;

If you are using posgres version 8.4 or higher you can make use of the array_arg function.
The array_arg function returns an array but it can be casted into text.
SELECT t1.product_id, t1.product, array_agg(t2.custom_id)
FROM Table1 t1, Table2 t2
WHERE t1.product_id = t2.product_id
If you are using postgres version 9.0 or higher you can make use of the string_agg function and your query could look like this
SELECT t1.product_id, t1.product, string_agg(t2.custom_id, ',')
FROM Table1 t1, Table2 t2
WHERE t1.product_id = t2.product_id

Related

Pair record with closest from join

I have the following tables:
id | detected
-----------+----------------
288 | 26817612
288 | 26817734
468 | 26817609
468 | 26817646
476 | 26817700
502 | 26817609
502 | 26817616
502 | 26817655
and
id | fulfilled
-----------+-----------------
288 | 26817616
288 | 26817635
468 | 26817623
468 | 26817659
476 | 26817706
502 | 26817621
502 | 26817627
502 | 26817663
What i need to do, is to JOIN these to tables by id, matching records from the first table, with its closest fulfilled counterpart.
For example:
id | detected | fulfilled
-------------------------
288| 26817612 | 26817616
288| 26817734 | 26817635
468| 26817609 | 26817623
... and so on.
Is there any way to do this with this data, or am i wasting my time and should gather new one?
I have created a solution at DB fiddle with just dataset for Id 288 and it should work for all other Id's as well. Here is the URL https://www.db-fiddle.com/f/vieqapnXDrrGzGeUA7GE5h/4
Here is final sql:
SELECT
s1.Id, s1.detected, s2.fulfilled
FROM
(SELECT
t1.Id, t1.detected, MIN(ABS(t1.detected - t2.fulfilled)) AS Diff
FROM
table1 t1
LEFT JOIN
table2 t2
ON t1.Id = t2.Id
Group by t1.Id, t1.detected) s1
LEFT JOIN
table2 s2
ON s1.Id = s2.Id
WHERE
s1.Diff = ABS(s1.detected - s2.fulfilled)
You seem to want to reduce the number of rows as well. To me, this suggests row_number():
select t12.*
from (select t1.*, t2.*fulfilled
row_number() over (partition by t1.id order by abs(t1.detected - t2.fulfilled)) as seqnum
from t1 join
t2
on t1.id = t2.id
) t12
where seqnum = 1;
One option you have, assuming both tables will always contain the same list of id values, is to use apply() and subtract the two values to get the closest match:
select *
from t1
cross apply(
select top (1) t2.fulfilled
from t2
where t2.id=t1.id
order by Abs(t1.detected-t2.fulfilled)
)t2

How to create a calculated column in access that is based in a conditional sum of another table

It is possible in MS ACCESS 2016 to create a column in a table that is a conditional SUM of another table?
Example
Table 1 - Columns
ID, NAME, TOTAL
Table 2 - Columns
ID, NAME, IDREF, CUSTO
Data:
Table 1
ID | Name | Total
---+-------+----------------------------------------------------------------
35 | Test | "SUM(CUSTO) of ALL ELEMENTS OF TABLE 2 WHERE table2.IDREF = table1.ID"
Table 2
ID | Name | IDREF | CUSTO
---+-------+-------+--------
1 | Test | 35 | 50
2 | Test | 35 | 30
3 | abcd | 12 | 30
4 | Test | 35 | 10
The result should be:
table 1
ID | Name | Total
---+------+------
35 | Test | 90 (50 + 30 + 10 from table 2 where idref = 35)
You can use a subquery:
select t1.*,
(select sum(t2.CUSTO)
from table2 as t2
where t2.idref = t1.id
) as total
from table1 as t1;
More efficiently, consider an aggregate subquery in JOIN to run only once and not SELECT subquery that runs for every row.
SELECT t1.*, agg.Total
FROM table1 as t1
INNER JOIN
( SELECT t2.idref, SUM(t2.CUSTO) AS Total
FROM table2 as t2
GROUP BY t2.idref
) AS agg
ON agg.idref = t1.id
Alternatively, replace subquery with exact saved query for even more efficiency per Allen Browne's optimizing query tips in MS Access:
A subquery will be considerably faster than a domain aggregate function. In most cases, a stacked query will be faster yet (i.e. another saved query that you include as a "table" in this query.)
SELECT t1.*, q.Total
FROM table1 as t1
INNER JOIN mySavedAggQuery q
ON q.idref = t1.id

Retrieve data from the same table if subId is an id of other item

I have a table that contains some records, and I would like to get only these records that have subID to a record with the id of the subID value. If there is no row with the id then do not take this row to the table. Also do not duplicate values if already in the table and do not look at rows that have subId 0 because they are as parents we can say so they do not have childs
----------------------------
ID | SUBID | NAME | ENABLED |
30 | 0 | EXP1 | TRUE |
55 | 30 | EXP2 | TRUE |
70 | 30 | EXP3 | FALSE |
99 | 42 | EXP4 | FALSE |
232| 0 | EXP5 | TRUE |
65 | 232 | EXP6 | TRUE |
-----------------------------
Expected result:
----------------------------
ID | SUBID | NAME | ENABLED |
30 | 0 | EXP1 | TRUE |
55 | 30 | EXP2 | TRUE |
70 | 30 | EXP3 | FALSE |
232| 0 | EXP5 | TRUE |
65 | 232 | EXP6 | TRUE |
-----------------------------
If someone could help me how to write this SQL statement in a good way I will be grateful.
You can use 'Exists':
SELECT T1.* FROM TEST T1
WHERE EXISTS (SELECT T2.ID FROM TEST T2 WHERE T2.ID = T1.SUBID)
OR EXISTS (SELECT T3.SUBID FROM TEST T3 WHERE T3.SUBID = T1.ID)
Test Result:
DB<>Fiddle
How about a union
select a.*
from have a
inner join have b
on a.subid=b.id
union
select b.*
from have a
inner join have b
on a.subid=b.id;
This can be actually pretty complicated, as you've evidently found out. I'd suggest a CTE and a UNION with your JOINs and aliases. It also looks like it'll need all that in a subquery to do a DISTINCT, too.
Without testing this, I'd image it looks something like this:
WITH MAIN AS (
SELECT ID, SUBID, NAME
FROM TABLE t
WHERE ENABLED = TRUE
)
SELECT DISTINCT ID, NAME
FROM (
SELECT ID, NAME
FROM MAIN
UNION
SELECT t.ID, t.NAME
FROM MAIN
LEFT JOIN TABLE t on MAIN.SUBID = t.ID
WHERE MAIN.SUBID <> 0
)
The outer select might not be needed if you do a distinct on each of the inner queries, but without testing it, I can't say for sure. I'd guess it would only DISTINCT the two lists separately, which isn't your intended result.
I'm kind of hoping someone else can come up with a less complicated version. I'd also suggest you do some more research on CTEs, UNIONs, aliases, and see if you can make this simpler on your own. But this should get you in the right direction.
BTW, I used a CTE (WITH MAIN AS) so that the query wouldn't be duplicated.
Try this script-
SELECT YT.*
FROM your_table YT
INNER JOIN (
SELECT DISTINCT(B.ID)
FROM your_table A
LEFT JOIN your_table B
ON A.SUBID = B.ID
WHERE B.ID IS NOT NULL
) C ON YT.ID = C.ID OR YT.SUBID = C.ID
By my understanding of what you are trying to do, you simply want:
SELECT * FROM myTable t1
WHERE SubID = 0
OR EXISTS (SELECT NULL FROM myTable t2 WHERE t2.id = t1.SubID)

Oracle Efficiently joining tables with subquery in FROM

Table 1:
| account_no | **other columns**...
+------------+-----------------------
| 1 |
| 2 |
| 3 |
| 4 |
Table 2:
| account_no | TX_No | Balance | History |
+------------+-------+---------+------------+
| 1 | 123 | 123 | 12.01.2011 |
| 1 | 234 | 2312 | 01.03.2011 |
| 3 | 232 | 212 | 19.02.2011 |
| 4 | 117 | 234 | 24.01.2011 |
I have multiple join query, one of the tables(Table 2) inside a query is problematic as it is a view which computes many other things, that is why each query to that table is costly. From Table 2, for each account_no in Table 1 I need the whole row with the greatest TX_NO, this is how I do it:
SELECT * FROM TABLE1 A LEFT JOIN
( SELECT
X.ACCOUNT_NO,
HISTORY,
X.BALANCE
FROM TABLE2 X INNER JOIN
(SELECT
ACCOUNT_NO,
MAX(TX_NO) AS TX_NO
FROM TABLE2
GROUP BY ACCOUNT_NO) Y ON X.ACCOUNT_NO = Y.ACCOUNT_NO) B
ON B.ACCOUNT_NO = A.ACCOUNT_NO
As I understand at first it will make the inner join for all the rows in Table2 and after that left join needed account_no's with Table1 which is what I would like to avoid.
My question: Is there a way to find the max(TX_NO) for only those accounts that are in Table1 instead of going through all? I think it will help to increase the speed of the query.
I think you are on the right track, but I don't think that you need to, and would not myself, nest the subqueries the way you have done. Instead, if you want to get each record from table 1 and the matching max record from table 2, you can try the following:
SELECT * FROM TABLE1 t1
LEFT JOIN
(
SELECT t.*,
ROW_NUMBER() OVER (PARTITION BY account_no ORDER BY TX_No DESC) rn
FROM TABLE2 t
) t2
ON t1.account_no = t2.account_no AND
t2.rn = 1
If you want to continue with your original approach, this is how I would do it:
SELECT *
FROM TABLE1 t1
LEFT JOIN TABLE2 t2
ON t1.account_no = t2.account_no
INNER JOIN
(
SELECT account_no, MAX(TX_No) AS max_tx_no
FROM TABLE2
GROUP BY account_no
) t3
ON t2.account_no = t3.account_no AND
t2.TX_No = t3.max_tx_no
Instead of using a window function to find the greatest record per account in TABLE2, we use a second join to a subquery instead. I would expect the window function approach to perform better than this double join approach, and once you get used to it can even easier to read.
If table1 is comparatiely less expensive then you could think of doing a left outer join first which would considerable decrease the resultset and from that pick the latest transaction id records alone
select <required columns> from
(
select f.<required_columns),row_number() over (partition by account_no order by tx_id desc ) as rn
from
(
a.*,b.tx_id,b.balance,b.History
from table1 a left outer join table2 b
on a.account_no=b.account_no
)f
)g where g.rn=1

How to get a single result with columns from multiple records in a single table?

Platform: Oracle 10g
I have a table (let's call it t1) like this:
ID | FK_ID | SOME_VALUE | SOME_DATE
----+-------+------------+-----------
1 | 101 | 10 | 1-JAN-2013
2 | 101 | 20 | 1-JAN-2014
3 | 101 | 30 | 1-JAN-2015
4 | 102 | 150 | 1-JAN-2013
5 | 102 | 250 | 1-JAN-2014
6 | 102 | 350 | 1-JAN-2015
For each FK_ID I wish to show a single result showing the two most recent SOME_VALUEs. That is:
FK_ID | CURRENT | PREVIOUS
------+---------+---------
101 | 30 | 20
102 | 350 | 250
There is another table (lets call it t2) for the FK_ID, and it is here that there is a reference
saying which is the 'CURRENT' record. So a table like:
ID | FK_CURRENT | OTHER_FIELDS
----+------------+-------------
101 | 3 | ...
102 | 6 | ...
I was attempting this with a flawed sub query join along the lines of:
SELECT id, curr.some_value as current, prev.some_value as previous FROM t2
JOIN t1 curr ON t2.fk_current = t1.id
JOIN t1 prev ON t1.id = (
SELECT * FROM (
SELECT id FROM (
SELECT id, ROW_NUMBER() OVER (ORDER BY SOME_DATE DESC) as rno FROM t1
WHERE t1.fk_id = t2.id
) WHERE rno = 2
)
)
However the t1.fk_id = t2.id is flawed (i.e. wont run), as (I now know) you can't pass a parent
field value into a sub query more than one level deep.
Then I started wondering if Common Table Expressions (CTE) are the tool for this, but then I've no
experience using these (so would like to know I'm not going down the wrong track attempting to use them - if that is the tool).
So I guess the key complexity that is tripping me up is:
Determining the previous value by ordering, but while limiting it to the first record (and not the whole table). (Hence the somewhat convoluted sub query attempt.)
Otherwise, I can just write some code to first execute a query to get the 'current' value, and then
execute a second query to get the 'previous' - but I'd love to know how to solve this with a single
SQL query as it seems this would be a common enough thing to do (sure is with the DB I need to work
with).
Thanks!
Try an approach with LAG function:
SELECT FK_ID ,
SOME_VALUE as "CURRENT",
PREV_VALUE as Previous
FROM (
SELECT t1.*,
lag( some_value ) over (partition by fk_id order by some_date ) prev_value
FROM t1
) x
JOIN t2 on t2.id = x.fk_id
and t2.fk_current = x.id
Demo: http://sqlfiddle.com/#!4/d3e640/15
Try out this:
select t1.FK_ID ,t1.SOME_VALUE as CURRENT,
(select SOME_VALUE from t1 where p1.id2=t1.id and t1.fk_id=p1.fk_id) as PREVIOUS
from t1 inner join
(
select t1.fk_id, max(t1.id) as id1,max(t1.id)-1 as id2 from t1 group by t1.FK_ID
) as p1 on t1.id=p1.id1