I have two tables and I want to join them with null values in it.
Sample data of my first table(A_TEST):
+--+----+
|ID|NAME|
+--+----+
| |a |
|1 |b |
|1 |c |
+--+----+
Sample data of my second table(B_TEST):
+--+----+
|ID|NAME|
+--+----+
|1 |d |
|2 |e |
|3 |f |
+--+----+
I need to achieve the result by joining a_test.id = b_test.id and if there is null values in it I need to fetch them too. So I tried to write query as below,
select a_test.id,a_test.name,b_test.id,b_test.name
from a_test,b_test
where (a_test.id = b_test.id
or a_test.id is null);
I got output as below,
+--+----+--+----+
|ID|NAME|ID|NAME|
+--+----+--+----+
| |a |1 |d |
| |a |2 |e |
| |a |3 |f |
|1 |b |1 |d |
|1 |c |1 |d |
+--+----+--+----+
But my expected result is, since id 1 is there in my a_test i need the corresponding row from b_test also.See output below
+--+----+--+----+
|ID|NAME|ID|NAME|
+--+----+--+----+
| |a |1 |d |
|1 |b |1 |d |
|1 |c |1 |d |
+--+----+--+----+
I tried with outer joins also but that also does not give me the expected output.
Your own query is almost correct (although you shouldn't use error-prone comma-separated joins that went out of fashion some twenty years ago). You are only missing the condition what must match in case of a_test.id is null (which is: the b_test.id must be in table a_test).
select
a.id as a_id,
a.name as a_name,
b.id as b_id,
b.name as b_name
from a_test a
join b_test b on
(a.id = b.id)
or
(a.id is null and b.id in (select id from a_test));
SQL fiddle: http://www.sqlfiddle.com/#!4/fae22/2.
However strange and meaningless your requirement is, this query gives you your expected result:
select A.*, B.*
from a_test A
join b_test B
on A.id = B.id
union all
select A.*, B.*
from a_test A
cross join b_test B
where A.id is null
and exists (
select 1
from a_test Ax
where Ax.id = B.id
)
order by 2, 4
;
Enjoy!
If a a_test.id NULL is supposed to be treated as 1 when joining, use COALESCE and a sub-query to find replacing value (to be figured out by yourself, just make sure it doesn't return more than one row):
select a_test.id,a_test.name,b_test.id,b_test.name
from a_test,b_test
where COALESCE(a_test.id,(select integervalue from sometable)) = b_test.id
select a_test.id,a_test.name,b_test.id,b_test.name
from a_test,b_test
where a_test.id = b_test.id(+)
But, what are you want see, when a_test.id is null or missing?
Related
Background
Forgive the title of this question, as I'm not really sure how to describe what I'm trying to do.
I have a SQL table, d, that looks like this:
+--+---+------------+------------+
|id|sex|event_type_1|event_type_2|
+--+---+------------+------------+
|a |m |1 |1 |
|b |f |0 |1 |
|c |f |1 |0 |
|d |m |0 |1 |
+--+---+------------+------------+
The Problem
I'm trying to write a query that yields the following summary of counts of event_type_1 and event_type_2 cut (grouped?) by sex:
+-------------+-----+-----+
| | m | f |
+-------------+-----+-----+
|event_type_1 | 1 | 1 |
+-------------+-----+-----+
|event_type_2 | 2 | 1 |
+-------------+-----+-----+
The thing is, this seems to involve some kind of transposition of the 2 event_type columns into rows of the query result that I'm not familiar with as a novice SQL user.
What I've tried
I've so far come up with the following query:
SELECT event_type_1, event_type_2, count(sex)
FROM d
group by event_type_1, event_type_2
But that only gives me this:
+------------+------------+-----+
|event_type_1|event_type_2|count|
+------------+------------+-----+
|1 |1 |1 |
|1 |0 |1 |
|0 |1 |2 |
+------------+------------+-----+
You can use a lateral join to unpivot the data. Then use conditional aggregate to calculate m and f:
select v.which,
count(*) filter (where d.sex = 'm') as m,
count(*) filter (where d.sex = 'f') as f
from d cross join lateral
(values (d.event_type_1, 'event_type_1'),
(d.event_type_2, 'event_type_2')
) v(val, which)
where v.val = 1
group by v.which;
Here is a db<>fiddle.
I have this table categories
|catId |catName|catParentID|catType|
-------------------------------------
|1 |cat1 |null |6 |
|2 |cat2 |null |9 |
|3 |cat3 |1 |6 |
|4 |cat4 |2 |9 |
|5 |cat5 |1 |6 |
|6 |cat6 |3 |8 |
the parents are in the same table with the sub categories only they have no parent.
i need to get all the sub categories that their parent's type is 6.
the output of the example above should look like this-
cat3
cat5
Given your data structure, this seems to work:
select c.*
from categories c
where c.catParentID is not null and -- has a parent
c.catType = 6;
However, that might not be a general solution. So you can use a self-join:
select c.*
from categories c join
categories cp
on c.catParentID = cp.catID
where cp.catType = 6;
SELECT *
FROM categories
WHERE cattype = 6
AND catparentid IS NOT NULL
The Simplest way is,
SELECT * FORM categories WHERE catParentId ='1' AND catType ='6'
Try this... (Based on your desired output)
SELECT t1.*
FROM tablename t1
LEFT JOIN tablename t2 ON t1.catparentid = t2.catid
WHERE t2.cattype = 6
AND t2.catparentid IS NULL
sql: I have a table like this:
+------+------+
|ID |Result|
+------+------+
|1 |A |
+------+------+
|2 |A |
+------+------+
|3 |A |
+------+------+
|1 |B |
+------+------+
|2 |B |
+------+------+
The output should be something like:
Output:
+------+-------+-------+
|ID |Result1|Result2|
+------+-------+-------+
|1 |A |B |
+------+-------+-------+
|2 |A |B |
+------+-------+-------+
|3 |A | |
+------+-------+-------+
How can I do this?
SELECT
Id,
MAX((CASE result WHEN 'A' THEN 'A' ELSE NULL END)) result1,
MAX((CASE result WHEN 'B' THEN 'B' ELSE NULL END)) result2,
FROM
table1
GROUP BY Id
results
+------+-------+-------+
|Id |Result1|Result2|
+------+-------+-------+
|1 |A |B |
|2 |A |B |
|3 |A |NULL |
+------+-------+-------+
run live demo on SQL fiddle: (http://sqlfiddle.com/#!9/e1081/2)
there are a few ways to do it.
None of tehm a are straight forward.
in theory, a simple way would be to create 2 temporary tables, where you separte the data, all the "A" resultas in one table and "B" in another table.
Then get the results with simple query. using JOIN.
if you are allowed to use some scrpting on the process then it is simpler, other wise you need a more complex logic on your query. And for you query to alwasy work, you need to have some rules like, A table always contains more ids than B table.
If you post your real example, it is easier to get better answers.
for this reason:
ID Name filename
1001 swapan 4566.jpg
1002 swapan 678.jpg
1003 karim 7688.jpg
1004 tarek 7889.jpg
1005 karim fdhak.jpg
output:
ID Name filename
1001 swapan 4566.jpg 678.jpg
1003 karim 7688.jpg fdhak.jpg
1004 tarek 7889.jpg ...
.. ... ... ...
I have a typical parent/child relationship table to represent folders. My challenge is using it in conjunction with another table.
The folder table is like this:
+--+----+--------+
|id|name|parentid|
+--+----+--------+
|1 |a |null |
+--+----+--------+
|2 |b |1 |
+--+----+--------+
|3 |c1 |2 |
+--+----+--------+
|4 |c2 |2 |
+--+----+--------+
The association table is like this:
+--+--------+
|id|folderid|
+--+--------+
|66|2 |
+--+--------+
|77|3 |
+--+--------+
so that where association.id = 66 has a relationship to folder.id = 2
What I need to do is find the association.id of the first ancestor with a record in the association table.. Using the example data above, given folder.id of 3 I expect to find 77; given folder.id of 2 or 4 I expect to find 66; any other folder.id value would find null.
Finding folder ancestry can be done with a common table expression like this:
WITH [recurse] (id,name,parentid,lvl) AS
(
select a.id,a.name,a.parentid,0 FROM folder AS a
WHERE a.id='4'
UNION ALL
select r.id,r.name,r.parentid,lvl+1 FROM folder as r
INNER JOIN [recurse] ON recurse.parentid = r.id
)
SELECT * from [recurse] ORDER BY lvl DESC
yielding the results:
+--+----+--------+---+
|id|name|parentid|lvl|
+--+----+--------+---+
|1 |a | |2 |
+--+----+--------+---+
|2 |b |1 |1 |
+--+----+--------+---+
|4 |c2 |2 |0 |
+--+----+--------+---+
To include the association.id I've tried using a LEFT JOIN in the recursive portion of the CTE, but this is not allowed by SQL Server.
What workaround do I have for this?
Or better yet, is the a way to query directly for the particular association.id? (e.g., without walking through the results of the CTE query that I have been attempting)
SELECT r.id, r.name, r.parentid, r.lvl, a.folderid, a.id as associationid
FROM [recurse] r
LEFT JOIN [association] a
ON r.id = a.folderid
WHERE a.folderId IS NOT NULL
ORDER BY lvl DESC
This will give you the records that have values in the association table. Then you could limit it to the first record that has a value or just grab the top result
Suppose I have a table of values and categories:
+--+-----+---+
|ID|value|cat|
+--+-----+---+
|0 |1 |0 |
+--+-----+---+
|1 |3 |0 |
+--+-----+---+
|2 |2 |1 |
+--+-----+---+
|3 |1.2 |1 |
+--+-----+---+
|4 |1 |1 |
+--+-----+---+
And I want to know, for each row, the ID of the row which matches the value most closely and belongs to the same category, and I also want to know the difference.
So for row ID=0 the correct answer would be ID=1, and the difference value would be 2. The correct output would be this:
+--+----------+----------+
|ID|difference|best match|
+--+----------+----------+
|0 |2 |1 |
+--+----------+----------+
|1 |2 |0 |
+--+----------+----------+
|2 |0.8 |3 |
+--+----------+----------+
|3 |0.2 |4 |
+--+----------+----------+
|4 |0.2 |3 |
+--+----------+----------+
I'm just learning about CROSS JOIN and while I'm sure this can be done I don't really know where to start.
You can do this with a self-join and making use of the ROW_NUMBER() function in conjunction with MIN():
;WITH cte AS (SELECT a.ID aID
,MIN(ABS(a.value - b.value)) diff
,ROW_NUMBER() OVER(PARTITION BY a.ID ORDER BY MIN(ABS(a.value - b.value)))RN
,b.ID bID
FROM Table1 a
JOIN Table1 b
ON a.cat = b.cat
AND a.ID <> b.ID
GROUP BY a.ID,b.ID)
SELECT aID
,diff
,bID Best_Match
FROM cte
WHERE RN = 1
Demo: SQL Fiddle
If you want to return multiple rows in case of a tie, you'd want to use RANK() instead of ROW_NUMBER()