select Parent Child Rows in same Table - sql

I have table structure like below
id |parent|value
1 | 0 | a |
2 | 1 | b |
3 | 4 | c |
4 | 0 | d |
5 | 0 | e |
I want to display only rows that have a relation parent child
like:
id |parent|value
1 | 0 | a |
2 | 1 | b |
3 | 4 | c |
4 | 0 | d |
every child should have a parent
every parent should have at least one child
This is my code but it does not work properly:
select a.id, a.parent,a.value
from myTable a inner join myTable b
on a.id = b.parent
union
select b.id, b.child,b.value
from myTable a inner join myTable b
on a.id = b.parent;

SELECT
*
FROM
yourTable
WHERE
parent != 0
OR EXISTS (SELECT *
FROM yourTable children
WHERE chilren.parent = yourTable.id
)
The first condition checks if the row points to a parent, and the second condition checks if the row has any children.

Related

How to fetch record from Table A which has not any approved status true on Table B

I have three table A , B and C and it structure is shown below
Table A
----------------------------
| id | Text_message_to_show|
----------------------------
| 1 | first demo message |
----------------------------
| 2 | second demo message |
----------------------------
Table B
------------------------------------
| id | request_id | approved_status |
------------------------------------
| 101 | 1 | 2 |
------------------------------------
| 102 | 1 | 1 |
------------------------------------
| 103 | 2 | 2 |
------------------------------------
| 104 | 2 | 2 |
------------------------------------
Table c
------------------------------------
| id | request_id | approved_status |
------------------------------------
| 501 | 1 | 2 |
------------------------------------
| 502 | 2 | 1 |
------------------------------------
Table B and Table C has foreign key request_id column which is reference id column of table A.Table Table A-> Table B has one to many relaionship and Table A->Table C has one to one relationship Now I have question is how to wrie sql query such that to fetch Table A record where no approved_status for request_id should be 2 in Table B And also Table C approved_status should not be 2
You can use not exists like following.
select *
from tablea ta
where not exists (
select 1
from tableb tb
where ta.id = tb.request_id
AND tb.approved_status = 2
)
You can use left join as follows:
Select a.*
From a
Left Join b on a.id = b.request_id and b.approved_status = 2
Left join c on a.id = c.request_id and c.approved_status = 2
Where coalesce(b.id,c.id) is null
select * from tablea ta
where not exists
(
select id from tableb tb where ta.id=tb.request_d and tb.approved_status = 2
)
This may help you out.

Expanding information from one row to all similarly grouped rows in SQL

I am not sure of the logic required to accomplish this, but I want to take a table like this...
+----+------+
| Id | Type |
+----+------+
| 10 | A |
| 10 | B |
| 10 | C |
| 20 | A |
| 20 | C |
+----+------+
...and end up with a table like this...
+----+------+---+---+---+
| Id | Type | A | B | C |
+----+------+---+---+---+
| 10 | A | 1 | 1 | 1 |
| 10 | B | 1 | 1 | 1 |
| 10 | C | 1 | 1 | 1 |
| 20 | A | 1 | 0 | 1 |
| 20 | C | 1 | 0 | 1 |
+----+------+---+---+---+
...where each Id will have new columns created to consolidate information about Type into every row of that Id. Since 10 has a row of types A, B, and C, then all rows that have an ID of 10 should have a 1/true in the new columns A, B and C.
I know how to do this on a per-row basis, but can't wrap my head around how to consolidate the information from multiple rows into each row of the same ID.
Try this below logic- Demo
SELECT *,
(SELECT COUNT(DISTINCT Type) FROM your_table B WHERE B.ID = A.Id and B.Type = 'A') A,
(SELECT COUNT(DISTINCT Type) FROM your_table C WHERE C.ID = A.Id and C.Type = 'B') B,
(SELECT COUNT(DISTINCT Type) FROM your_table D WHERE D.ID = A.Id and D.Type = 'C') C
FROM your_table A
And just another option- Demo
SELECT *,
SUM(CASE WHEN Type= 'A' THEN 1 ELSE 0 END) OVER(PARTITION BY Id) A,
SUM(CASE WHEN Type= 'B' THEN 1 ELSE 0 END) OVER(PARTITION BY Id) B,
SUM(CASE WHEN Type= 'C' THEN 1 ELSE 0 END) OVER(PARTITION BY Id) C
FROM your_table

How to select only the first group of results, after custom sorting?

In a hypothetical "items" table, the "type" values have an application-defined
priority (order): B before C before A. This priority is not part of the
database and can change between queries.
id | owner_id | type | name
----+----------+------+----------
1 | 1 | A | a item 1
2 | 1 | A | a item 2
3 | 1 | B | b item 1
4 | 1 | B | b item 2
5 | 1 | C | c item 1
6 | 1 | C | c item 2
7 | 1 | D | d item 1
8 | 2 | A | a item 3
9 | 2 | C | c item 3
I can get a list for one item owner, sorted by type priority:
id | type | name
----+------+----------
3 | B | b item 1
4 | B | b item 2
5 | C | c item 1
6 | C | c item 2
1 | A | a item 1
2 | A | a item 2
SQL:
SELECT id,
type,
name
FROM items
WHERE owner_id = 1
AND type IN ('A', 'B', 'C')
ORDER BY type != 'B',
type != 'C',
type != 'A',
name;
Now I would like to select only the first group of types (the two B items). If
there are no B items, I want all the C items, and so on.
I could use a separate query or a self-join or a CTE to find the top type,
but I was wondering if there is a simpler or more elegant way to get only the
first group of results, after ORDER BY has been applied.
For example, if I could rank the groups, I could just select the rank 1 from
an outer query, but I can't seem to get the partitioning/ranking right. When
I select
dense_rank() OVER (PARTITION BY type)
all values for dense_rank() are 1.

SQL to identify duplicates in a tree-like structure

I am looking for a solution for this (MS SQL 2008, btw):
ID | ParentID | Feature_1 | Feature_2
+-----+------------+------------+----------+
1 | NULL | A | B
2 | 1 | A | B
3 | 1 | A | C
4 | 2 | A | C
Whenever a child (a record with a ParentID) has the same set of features (Feature_1 and Feature_2) than its parent, I want to ignore it, essentially not show it in my select *.
So the result set should be
ID | ParentID | Feature_1 | Feature_2
+-----+------------+------------+----------+
1 | NULL | A | B
3 | 1 | A | C
4 | 2 | A | C
Note that ID=2 is dropped, but ID=4 is displayed because it has a different set of features than its parent had.
Any help would be much appreciated!
SELECT
Child.ID,
Child.ParentID,
Child.Feature_1,
Child.Feature_2
FROM
MyTable AS Child
LEFT OUTER JOIN MyTable AS Parent
ON Child.ParentID = Parent.ID
WHERE
Parent.Feature_1 <> Child.Feature_1
OR Parent.Feature_2 <> Child.Feature_2
OR Child.ParentID IS NULL
ORDER BY
Child.ID
SELECT *
FROM table A
WHERE a.ParentID IS NULL OR NOT EXISTS (SELECT 1
FROM table b
WHERE a.ParentID = b.ID
AND a.Feature_1 = b.Feature_1 AND a.Feature_2 = b.Feature_2)

Single row for multiple case in a select

I need a solution for the below senario
I have a table temp with columns: a, b, c, d and the data looks like this:
TABLE TEMP
+---+----+----+----+
|a | b | c | d |
+===+====+====+====+
| 1 | 1 | 1 | m |
| 1 | 2 | 1 | d |
| 1 | 3 | 1 | w |
| 2 | 1 | 1 | m |
| 2 | 2 | 1 | d |
| 2 | 2 | 1 | w |
+---+----+----+----+
QUERY
SELECT CASE WHEN B=1 AND C=1 THEN D END as T1,
CASE WHEN B=2 AND C=1 THEN D END as T2,
CASE WHEN B=3 AND C=1 THEN D END as T3
FROM TEMP
WHERE A=1
The above query gives multiple rows with null values where value is not present
I need a result set with a single row that looks like this:
Expected Result
+------+-------+------+
| T1 | T2 | T3 |
+======+=======+======+
| m | d | w |
+------+-------+------+
Do like this (using CTE)
QUERY
WITH
CTE1 as (select top 1 d as T1 from temp where b=1 and c=1),
CTE2 as (select top 1 d as T2 from temp where b=2 and c=1),
CTE3 as (select top 1 d as T3 from temp where b=3 and c=1)
select CTE1.*, CTE2.*, CTE3.*
FROM CTE1 CROSS JOIN CTE2 CROSS JOIN CTE3
SQL fiddle
About the multiple CTE
Please let me whether it works!