How do I use a column value in a substrings where clause - sql

03-30 13:17]
I'm trying to use a t-sql against SQL-Server 2005 with asp 3.0. What I want to do is first select all rows that match a certain condition and then I want to know how how many children are connected to that row based on it's ChildID.
This can of course be done by just doing two queries against the db one to get the matching rows for the Parent and one for each row that was found to know how many children have that as Parent.
I have two tables, table1 contains parents and children and table2 contains the information and the id here is ofcourse the id that is saved in parent and children in table1.
Now I want to first find all the children to a certain parent, and in the same sql-statement I want to know how many children is connected to each child.
So Parent 807 has two children, 808 and 809. 808 has 5 children and 809 has 72 children, how can I with one statement get both the information of children 808 and 809 and the numer of children connected to each of them.
My SQL looks like this (gets the children to parent 807)
SELECT Parent, Child, ID, FieldX, FieldY
FROM Tabel1 INNER JOIN Tabel2 ON Parent = ID
WHERE (Parent = 807)
The statement I use to get the numer of children connected to f.ex. 808 is as follows.
SELECT COUNT(*) AS AntalPoster
FROM Tabel1 INNER JOIN Tabel2 ON Child = ID
WHERE (Parent = 808)
What I would like to do is the following, but I would like to substitute the value 808 with the value each record gives me for the child aka SearchID.
SELECT Parent, Child AS SearchID, ID, FieldX, FieldY,
(SELECT COUNT(*) AS [Antal sidor]
FROM Tabel1 INNER JOIN Tabel2 ON Child = ID
WHERE (Parent = 808)) AS AntalPoster
FROM Tabel1 INNER JOIN Tabel2 ON Child = ID
WHERE (Parent = 807)
The problem I get is that "Invalid column name 'SearchID'", what I can understand is that I can't get the value that I find in SerachID to be used as a value in the next SQL-statements where clause.
Is this possible, and if so how?
Thanks in advance.

So, I understand, basically Table1 contains hierarchy information, and Table2 details.
Assuming that, here's my approach:
SELECT
h.Parent,
h.ChCount,
d.* /* you may want to expand it to a specific Table2 column list */
FROM (
/* first, get the children and their child counts */
SELECT
p.Parent,
p.Child,
COUNT(*) AS ChCount
FROM Table1 p
INNER JOIN Table1 c ON p.Child = c.Parent
GROUP BY p.Parent, p.Child
WHERE p.Parent = 807
) h
/* next, get the children's details */
INNER JOIN Table2 d ON h.Child = d.ID

Now I want to first find all the children to a certain parent, and in the same sql-statement I want to know how many children is connected to each child.
This is a way to do that.
declare #Table1 table (Table1ID int, ParentID int)
-- Root
insert into #Table1 values(807, null)
-- Children to 807
insert into #Table1 values(808, 807)
insert into #Table1 values(809, 807)
-- Children to 808
insert into #Table1 values(810, 808)
-- Children to 809
insert into #Table1 values(811, 809)
insert into #Table1 values(812, 809)
select
T1.*,
(select count(*)
from #Table1 as T2
where T1.Table1ID = T2.ParentID) as ChildCount
from #Table1 as T1
where T1.ParentID = 807
Result
Table1ID ParentID ChildCount
----------- ----------- -----------
808 807 1
809 807 2

Replace
WHERE (Parent = SearchID))
by
WHERE (Parent = ParentID))
But you're better of using
SELECT Parent, Child, ID, FieldX, FieldY, COUNT(*) AS AntalPoster
FROM Tabel1 INNER JOIN Tabel2 ON Child = ID
WHERE (Parent = [ParentID])
GROUP
BY Parent, Child, ID, FieldX, FieldY;

If you define a "alias" for a column you can't use this name inside the query earlier than within a group by or order by clause.
As is your example SearchID is just a name for column Child you should use WHERE (PARENT = Child)

You're kinda close.
SELECT Parent_ID, COUNT(*) AS AntalPoster FROM Tabel1 INNER JOIN Tabel2 ON Child = ID
Group by Parent_ID
Now I don' quite understand from reading your question what the 'ID' field is called...but the results of this query should give the Parent_ID along with the count of the number of child records (If I've read your setup corectly). Join to that subquerty to get the count.
SELECT Parent, Child.AntalPoster, ID, FieldX, FieldY
FROM Tabel1 INNER JOIN Tabel2 ON Parent = ID
inner join (SELECT Parent_ID, COUNT(*) AS AntalPoster FROM Tabel1 INNER JOIN Tabel2 ON Child = ID Group by Parent_ID) child on child.id = t1.ID
WHERE (Parent = 807)
Whats really confusing me in your example...if I'm still off with what you're going for...quickly giving us the schema would help. Is the table setup so it has Parent, Child, ID? If so, how does the work? I'd expect Parent_ID, Child_ID...bit confused on the third "ID" column, what does it hold thats unique from the parent,child columns that already exist?.
In any case, the logic is setup a subquery so it reads Key , Count(1). Then join to that subquery on the Key to obtain the count value the subquery returns.

Related

Having trouble self joining a table with NULL values

I have a single table that has the columns: personID, name, parentID1 and parentID2
Essentially I am looking to use this table to find a childs parent(s)
Not every child has both parents, so these values are NULL in the table. I have tried using self joins but it just is not working out for me.
TABLE
Here is what the table should look like:
Need to use LEFT joins so each row is returned even if the there is no match in the right table
List Parents for Each Person Even if 1 Parent is NULL
SELECT A.[name] AS Child
,B.[name] AS Parent1
,C.[name] AS Parent2
FROM YourTable AS A
LEFT JOIN YourTable AS B
ON A.ParentID1 = B.PersonID
LEFT JOIN YourTable AS C
ON A.ParentID2 = C.PersonID
WHERE A.ParentID1 IS NOT NULL
OR A.ParentID2 IS NOT NULL

SQL - return a value referenced by initial value from same table

I'm sure this has been asked before, but I can't seem to find any questions that help.
Here's an example of a table:
ID Name Parent ID
---------------------------
1 Ice cream 3
2 Chips 4
3 Sweets null
I'm trying to figure out how to write a single query which, given ID=1, will return me rows 1 and 3. Is this possible without making two queries?
Also, is there a way to return the information of the parent as a custom column? So, rather than returning 2 rows, returning the row where id=1 with parent_id=3 added on?
You can use union all and exists:
select * from mytable where parent_id = 3
union all
select t.*
from mytable t
where exists (select 1 from mytable t1 where t1.parent_id = t.id and t.parent_id = 3)
If you want to do this over multiple levels of hierarchy, then you would typically use a recursive query. The syntax slightly varies accross databases (and not all of them support recursion), but the idea is:
with recursive cte as (
select * from mytable where parent_id = 3
union all
select t.*
from cte c
inner join mytable t on t.parent_id = c.id
)
select * from cte
This is how a straight up noob would do it. Hold tight for someone to give a better way
SELECT ID, Name, Parent_ID
FROM table
WHERE ID = 1
UNION
SELECT ID, Name, Parent_ID
FROM table
WHERE ID = (SELECT Parent_ID FROM table WHERE ID = 1)
Are you looking for something like this?:
select child.ID, child.Name, parent.ID as ParentId, parent.Name as ParentName
from T child left outer join T parent on parent.Id = child.parent_id;

Is it possible to use SELECT after WHERE

I have 2 tables: 1 master table and 1 that I'm trying to put together.
TABLE1: ID (AUTOINCREMENT) NAME PARENT
TABLE2: ID(AUTOINCREMENT) PARENT CHILD
SQL code:
INSERT INTO TABLE2 (PARENT, CHILD)
SELECT TABLE1.PARENT, TABLE1.ID
FROM TABLE1
WHERE TABLE1.PARENT = (SELECT DISTINCT TABLE1.PARENT FROM TABLE1)
So I want my query to go over all the PARENTs and one by one get all its children.
Obviously it's not working and it is returning only the first PARENT and its children IDs
Yes you can, using IN instead of =.
Try this:
INSERT INTO TABLE2 (PARENT, CHILD)
SELECT TABLE1.PARENT, TABLE1.ID
FROM TABLE1
WHERE TABLE1.PARENT IN (SELECT DISTINCT TABLE1.PARENT FROM TABLE1)
That query would produce the exact same results as the much simpler:
INSERT INTO TABLE2 (PARENT, CHILD)
SELECT PARENT, ID
FROM TABLE1
The subquery in the where clause has no effect. It's basically saying, please insert parent and id from table 1 where parent and id are in table 1. They will all be.
Now if you were using a separate table in the subquery this might make sense. But even then I would suggest simply joining like so:
INSERT INTO TABLE2 (PARENT, CHILD)
SELECT TABLE1.PARENT, TABLE1.ID
FROM TABLE1
JOIN
(SELECT DISTINCT PARENT FROM TABLE2) TABLE2
ON TABLE1.PARENT = TABLE2.PARENT

Getting all the children of a parent using MSSQL query

I have the following data in my database:
Parent Child
101 102
101 103
101 104
101 105
101 106
My parameter is 106. And using the parameter I want to retrieve all the other children under its parent which is 101. I tried using the recursive method but it didn't work given the following data. Is there another way to formulate a query?
Assuming you want to get siblings of the value #p0, you can use a simple self-join:
SELECT p.Child
FROM Table1 c
INNER JOIN Table1 p ON c.Parent = p.Parent
WHERE c.Child = #p0
AND p.Child <> #p0
The not-equal clause here makes sure you get siblings not including the value you searched for. Remove it as necessary.
SQL Fiddle example
Since you mention recursion though, perhaps you want the entire tree starting at the parent of the value #p0. In which case, you can use a recursive CTE:
WITH parent AS (
SELECT Parent
FROM Table1
WHERE Child = #p0
), tree AS (
SELECT x.Parent, x.Child
FROM Table1 x
INNER JOIN parent ON x.Parent = parent.Parent
UNION ALL
SELECT y.Parent, y.Child
FROM Table1 y
INNER JOIN tree t ON y.Parent = t.Child
)
SELECT Parent, Child
FROM tree
SQL Fiddle examples using your data and
with additional data to demonstrate the recursive CTE
SQL Authority has a blog with a very nice explanation of how to perform a Hierarchical Query using a Recursive CTE
http://blog.sqlauthority.com/2012/04/24/sql-server-introduction-to-hierarchical-query-using-a-recursive-cte-a-primer/
Regards
select child
from my_table T1
where exists (select 1 from my_table T2 where child = #parameter and T1.parent = T2.parent)
WITH parent AS (
SELECT Parent
FROM Table1
WHERE Child = #p0
), tree AS (
SELECT x.Parent, x.Child
FROM Table1 x
INNER JOIN parent ON x.Parent = parent.Parent
UNION ALL
SELECT y.Parent, y.Child
FROM Table1 y
INNER JOIN tree t ON y.Parent = t.Child
)
SELECT Parent, Child
FROM tree

How to select parent rows that doesn't have child and child that has parent rows

I have a little bit complicated query.
I have table
tbl_Categories {CategoryID, Name, CategoryId_fk}
and it it a self referenced table.
When CategoryId_fk is NULL then that row is parent when there is a value that it is a child.
I have problem to select all children (it's where CategoryId_fk is not null) and rows where CategoryId_fk is null and doesn't have children.
I tried something but doesn't work:
SELECT a.*
FROM tbl_Categories a
WHERE NOT EXISTS (
SELECT 1 FROM tbl_Categories b
WHERE b.CategoryId_fk= a.CategoryId_fk
)
You have matched both b and a on the foreign key.
I might be misinterpreting your question, most of the times users want to find all childs for a given parent, but below query returns what I think you need.
/* All parents without children */
SELECT a.*
FROM tbl_Categories a
WHERE NOT EXISTS (
SELECT *
FROM tbl_Categories b
WHERE b.CategoryId_fk = a.CategoryId
)
/* All children */
UNION ALL
SELECT a.*
FROM tbl_Categories a
WHERE CategoryId_fk IS NOT NULL