SQL right join, force return only one value from right hand side - sql

table 1
---
id , name
table2
---
id , activity, datefield
table1 'right join' table2 will return more than 1 results from right table (table2) . how to make it return only "1" result from table2 with the highest date

You write poor information about your problem, But I'll try to make an example to help you.
You have a table "A" and a table "B" and you need to fetch the "top" date of table "B" that is related with table "A"
Example tables:
Table A:
AID| NAME
----|-----
1 | Foo
2 | Bar
Table B:
BID | AID | DateField
----| ----| ----
1 | 1 | 2000-01-01
2 | 1 | 2000-01-02
3 | 2 | 2000-01-01
If you do this sql:
SELECT * FROM A RIGHT JOIN B ON B.ID = A.ID
You get all information of A and B that is related by ID (that in this theoretical case is the field that is common for both tables to link the relation)
A.AID | A.NAME | B.BID | B.AID | B.DateField
------|--------|-------|-------|--------------
1 | Foo | 1 | 1 | 2000-01-01
1 | Foo | 2 | 1 | 2000-01-02
2 | Bar | 3 | 2 | 2000-01-01
But you require only the last date for each element of the Table A (the top date of B)
Next if you need to get only the top DATE you need to group your query by the B.AID and fetch only the top date
SELECT
B.AID, First(A.NAME), MAX(B.DateField)
FROM
A RIGHT JOIN B ON B.ID = A.ID
GROUP BY
B.AID
And The result of this operation is:
B.AID | A.NAME | B.DateField
------|--------|--------------
1 | Foo | 2000-01-02
2 | Bar | 2000-01-01
In this result I removed some fields that are duplicated (like A.AID and B.AID that is the relationship between the two tables) or are not required.
Tip: this also works if you have more tables into the sql. The sql "makes" the query and next applies a grouping for using the B to limit the repetitions of B to the top date.

right join table2 on on table1.id to to select id, max = max(date) from table2

Analytics!
Test data:
create table t1
(id number primary key,
name varchar2(20) not null
);
create table t2
(id number not null,
activity varchar2(20) not null,
datefield date not null
);
insert into t1 values (1, 'foo');
insert into t1 values (2, 'bar');
insert into t1 values (3, 'baz');
insert into t2 values (1, 'foo activity 1', date '2009-01-01');
insert into t2 values (2, 'bar activity 1', date '2009-01-01');
insert into t2 values (2, 'bar activity 2', date '2010-01-01');
Query:
select id, name, activity, datefield
from (select t1.id, t1.name, t2.id as t2_id, t2.activity, t2.datefield,
max(datefield) over (partition by t1.id) as max_datefield
from t1
left join t2
on t1.id = t2.id
)
where ( (t2_id is null) or (datefield = maxdatefield) )
The outer where clause will filter out all but the maximum date from t2 tuples, but leave in the null row where there was no matching row in t2.
Results:
ID NAME ACTIVITY DATEFIELD
---------- -------- ------------------- -------------------
1 foo foo activity 1 2009-01-01 00:00:00
2 bar bar activity 2 2010-01-01 00:00:00
3 baz

To retrieve the Top N records from a query, you can use the following syntax:
SELECT *
FROM (your ordered by datefield desc query with join) alias_name
WHERE rownum <= 1
ORDER BY rownum;
PS: I am not familiar with PL/SQL so maybe I'm wrong

my solution is
select from table1 right join table2 on (table1.id= table2.id and table2.datefiled= (select max(datefield) from table2 where table2.id= table1.id) )

Related

SQL counting columns with same userID

I have two tables. Table 1 contains content_id's that meets a certain criteria. Table 2 contains the content_id, content, and related user_id. They share a content_id field. I would like to produce a list of who has the most entries in Table 1.
Example
Table 1
content_id {1, 2, 3, 4, 5, 6}
Table 2
content_id|user_id { 1|2 , 2|3 , 3|2 , 4|1 , 5|3, 6|2 }
Desired results
user 2 has 3 entries
user 3 has 2 entries
user 1 has 1 entry
I imagine I need to INNER JOIN the two tables by content_id and then somehow use COUNT or similar?
Assuming you want to "filter" by the content of t1, one possibility is:
create table t1 (content_id int);
insert into t1 values (2, 3, 4, 5, 6);
-- note I ommitted 1 so not all values are present
create table t2 (content_id int, user_id int);
insert into t2 (values (1,2), (2,3) , (3,2) , (4,1) , (5,3), (6,2) );
select user_id, count(*) from t2 where exists (select 1 from t1 where content_id=t2.content_id) group by user_id;
-- output:
user_id | count
---------+-------
3 | 2
2 | 2
1 | 1
(3 rows)
-- OR
select user_id, count(*) from (select * from t2 except select 1 as user_id, content_id from t1) AS filtered group by user_id;
-- output:
user_id | count
---------+-------
3 | 2
2 | 2
1 | 1
(3 rows)
But other answers are already doing this too.
Here is the code snippet that will produce your desired result:
Select
tb2.user_id,count(tb2.content_id)
From table1 tb1
Inner join table2 tb2
on tb1.content_id=tb2.content_id
group by tb2.user_id
Are you looking for a simple group by?
select user_id, count(*)
from table2
group by user_id;
EDIT:
If you want to restrict the content ids, I recommend exists:
select t2.user_id, count(*)
from table2 t2
where exists (select 1
from table1 t1
where t1.content_id = t2.content_id
)
group by user_id;
I hope this what you looking for and help you
select user_id, count(`content_id`) from table2 t2
where exists (select t1.content_id from table1 t1
where t1.content_id=t2.content_id)
group by user_id order BY count(`content_id`) DESC;
+---------+---------------------+
| user_id | count(`content_id`) |
+---------+---------------------+
| 2 | 3 |
| 3 | 2 |
| 1 | 1 |
+---------+---------------------+

How to join two tables and show source?

How to join values from two tables ...
Table_1:
ID | Value
----------
10 | Dog
27 | Cat
Table_2:
ID | Value
----------
27 | Cat
My SQL... (Microsoft Access 2016)
SELECT ID, VALUE , "YES" AS Table_1, NULL AS Table_2
FROM Table_1
UNION
SELECT ID, VALUE, NULL AS Table_1, "YES" AS Table_2
FROM Table_2
...returns this result:
ID | Value | Table_1 | Table_2
------------------------------
10 | Dog | YES |
27 | Cat | YES |
27 | Cat | | YES
But I would like to get a result like this:
ID | Value | Table_1 | Table_2
------------------------------
10 | Dog | YES |
27 | Cat | YES | YES
You can use aggregation and union all:
select id, value, max(table_1) as table_1, max(table_2) as table_2
from (select ID, VALUE , "YES" AS Table_1, NULL AS Table_2
from Table_1
union
select ID, VALUE, NULL AS Table_1, "YES" AS Table_2
from Table_2
) t
group by id, value;
The alternative in SQL is a FULL JOIN, but MS Access does not support full joins.
You can make a list of table1 + table2 values and then check if the values exists in table2 or 2 using simple jeft join.
select
base.*,
iif(isnull(t.value), null, 'YES') table1,
iif(isnull(t2.value), null, 'YES') table2
from
(
Select value from Table_1 -- if you have duplicate values add groupby here
union
select value from Table_2
) base -- Make a collection of values from table1 and 2
left join Table_1 T on base.value = T.value
left join Table_2 T2 on base.value = T2.value;
Not sure if you can open above query in design view but the query should work in access. to be design view friendly, you need to make a query object for the base and then you can simply do left joins and iifs

SQL query to fetch IDs present only after a certain date

Tables look like this :-
Table A
------------------------
ID | C_Start_Date
------------------------
1 | 2018-03-10
2 | 2018-03-15
Table B
----------------------------
ID | Invoice_Date
----------------------------
1 | 2018-01-15
1 | 2018-02-15
1 | 2018-03-15
2 | 2018-04-01
2 | 2018-04-04
I have to fetch ONLY those Id's which have Invoice_Date later than their C_Start_Date.
For example, from the above table, the query should fetch only '2' as '1' has an entry in Table B with Invoice_Date earlier than its C_Start_Date.
Working query:
SELECT DISTINCT ID FROM A
WHERE ID NOT IN(
SELECT DISTINCT A.ID FROM A
INNER JOIN B ON A.ID = B.ID
WHERE B.INVOICEDATE < A.STARTDATE)
Fiddle for you to play and try around -> https://www.db-fiddle.com/f/kXXXJopWvsmHccdnPAgdmv/0
If I understand your requisites the below example will solve your problem (written in TSQL)
declare #TableA as table
(
ID int not null
,C_Start_Date date not null
)
declare #TableB as table
(
ID int not null
,Invoice_Date date not null
)
insert into #TableA
values
(1,'2018-03-10')
,(2,'2018-03-15')
insert into #TableB
values
(1,'2018-01-15')
,(1,'2018-02-15')
,(1,'2018-03-15')
,(2,'2018-04-01')
,(2,'2018-04-04')
select a.ID
from #TableA a
where not exists
(
select * from #TableB b where b.ID = a.ID and b.Invoice_Date < a.C_Start_Date
)
while the same be achieved with DISTINCT and a simple JOIN I utilised EXISTS as it generaly performs better than aggregates and distincts..

MS SQL Where one column is x or y and both returned

I have a table as follows with dates in. The table has many more records but simplified for asking purposes:
Name | Date | Grade
Person 1 | 01-01-2001 | B
Person 1 | 31-01-2001 | A
Person 2 | 01-01-2001 | C
Person 3 | 31-01-2001 | A
I want to return both records for Person 1 but not either of the other two. AND returns nothing obviously and OR returns everything. I want to search on the date not the grade or the person.
So the result would be:
Name | Date | Grade
Person 1 | 01-01-2001 | B
Person 1 | 31-01-2001 | A
One simple way to handle this is to aggregate by person and then assert that the two dates of interest are both present:
SELECT t1.*
FROM yourTable t1
INNER JOIN
(
SELECT Name
FROM yourTable
WHERE Date IN ('2001-01-01', '2001-01-31')
GROUP BY Name
HAVING COUNT(DISTINCT Date) = 2
) t2
ON t1.Name = t2.Name
You can uses EXISTS to return a row if there exists another row with that name, having the other A/B grade.
select t1.*
from tablename t1
where t1.Date in ('2001-01-01', '2001-01-31')
and exists (select 1 from tablename t2
where t2.Name = t1.Name
and t2.Date in ('2001-01-01', '2001-01-31')
and t2.Date <> t1.Date)

Merge two rows in SQL

Assuming I have a table containing the following information:
FK | Field1 | Field2
=====================
3 | ABC | *NULL*
3 | *NULL* | DEF
is there a way I can perform a select on the table to get the following
FK | Field1 | Field2
=====================
3 | ABC | DEF
Thanks
Edit: Fix field2 name for clarity
Aggregate functions may help you out here. Aggregate functions ignore NULLs (at least that's true on SQL Server, Oracle, and Jet/Access), so you could use a query like this (tested on SQL Server Express 2008 R2):
SELECT
FK,
MAX(Field1) AS Field1,
MAX(Field2) AS Field2
FROM
table1
GROUP BY
FK;
I used MAX, but any aggregate which picks one value from among the GROUP BY rows should work.
Test data:
CREATE TABLE table1 (FK int, Field1 varchar(10), Field2 varchar(10));
INSERT INTO table1 VALUES (3, 'ABC', NULL);
INSERT INTO table1 VALUES (3, NULL, 'DEF');
INSERT INTO table1 VALUES (4, 'GHI', NULL);
INSERT INTO table1 VALUES (4, 'JKL', 'MNO');
INSERT INTO table1 VALUES (4, NULL, 'PQR');
Results:
FK Field1 Field2
-- ------ ------
3 ABC DEF
4 JKL PQR
There are a few ways depending on some data rules that you have not included, but here is one way using what you gave.
SELECT
t1.Field1,
t2.Field2
FROM Table1 t1
LEFT JOIN Table1 t2 ON t1.FK = t2.FK AND t2.Field1 IS NULL
Another way:
SELECT
t1.Field1,
(SELECT Field2 FROM Table2 t2 WHERE t2.FK = t1.FK AND Field1 IS NULL) AS Field2
FROM Table1 t1
There might be neater methods, but the following could be one approach:
SELECT t.fk,
(
SELECT t1.Field1
FROM `table` t1
WHERE t1.fk = t.fk AND t1.Field1 IS NOT NULL
LIMIT 1
) Field1,
(
SELECT t2.Field2
FROM `table` t2
WHERE t2.fk = t.fk AND t2.Field2 IS NOT NULL
LIMIT 1
) Field2
FROM `table` t
WHERE t.fk = 3
GROUP BY t.fk;
Test Case:
CREATE TABLE `table` (fk int, Field1 varchar(10), Field2 varchar(10));
INSERT INTO `table` VALUES (3, 'ABC', NULL);
INSERT INTO `table` VALUES (3, NULL, 'DEF');
INSERT INTO `table` VALUES (4, 'GHI', NULL);
INSERT INTO `table` VALUES (4, NULL, 'JKL');
INSERT INTO `table` VALUES (5, NULL, 'MNO');
Result:
+------+--------+--------+
| fk | Field1 | Field2 |
+------+--------+--------+
| 3 | ABC | DEF |
+------+--------+--------+
1 row in set (0.01 sec)
Running the same query without the WHERE t.fk = 3 clause, it would return the following result-set:
+------+--------+--------+
| fk | Field1 | Field2 |
+------+--------+--------+
| 3 | ABC | DEF |
| 4 | GHI | JKL |
| 5 | NULL | MNO |
+------+--------+--------+
3 rows in set (0.01 sec)
I had a similar problem. The difference was that I needed far more control over what I was returning so I ended up with an simple clear but rather long query. Here is a simplified version of it based on your example.
select main.id, Field1_Q.Field1, Field2_Q.Field2
from
(
select distinct id
from Table1
)as main
left outer join (
select id, max(Field1)
from Table1
where Field1 is not null
group by id
) as Field1_Q on main.id = Field1_Q.id
left outer join (
select id, max(Field2)
from Table1
where Field2 is not null
group by id
) as Field2_Q on main.id = Field2_Q.id
;
The trick here is that the first select 'main' selects the rows to display. Then you have one select per field. What is being joined on should be all of the same values returned by the 'main' query.
Be warned, those other queries need to return only one row per id or you will be ignoring data
if one row has value in field1 column and other rows have null value then this Query might work.
SELECT
FK,
MAX(Field1) as Field1,
MAX(Field2) as Field2
FROM
(
select FK,ISNULL(Field1,'') as Field1,ISNULL(Field2,'') as Field2 from table1
)
tbl
GROUP BY FK
My case is I have a table like this
---------------------------------------------
|company_name|company_ID|CA | WA |
---------------------------------------------
|Costco | 1 |NULL | 2 |
---------------------------------------------
|Costco | 1 |3 |Null |
---------------------------------------------
And I want it to be like below:
---------------------------------------------
|company_name|company_ID|CA | WA |
---------------------------------------------
|Costco | 1 |3 | 2 |
---------------------------------------------
Most code is almost the same:
SELECT
FK,
MAX(CA) AS CA,
MAX(WA) AS WA
FROM
table1
GROUP BY company_name,company_ID
The only difference is the group by, if you put two column names into it, you can group them in pairs.
SELECT Q.FK
,ISNULL(T1.Field1, T2.Field2) AS Field
FROM (SELECT FK FROM Table1
UNION
SELECT FK FROM Table2) AS Q
LEFT JOIN Table1 AS T1 ON T1.FK = Q.FK
LEFT JOIN Table2 AS T2 ON T2.FK = Q.FK
If there is one table, write Table1 instead of Table2