Find all records that share specific comment - sql

I have an existing table1:
User Comment Group
---------------------
1 foo a
2 bar a
3 baz b
4 123 a
5 bar c
6 foo d
7 654 a
Assume that I need to select all Users with Comment foo
select * from [table1] t1 where t1.[Comment] = 'foo';
User Comment Group
---------------------
1 foo a
6 foo d
Now I want to find all the users in the same Groups:
User Comment Group
---------------------
1 foo a
2 bar a
4 123 a
6 foo d
How can I do this? I thought like this:
select t1.*
from [table1] t1
left join [table1] t2 on t1.[User] = t2.[User]
and t1.[Comment] = 'foo'
But this is returning all records in [table1]. What am I doing wrong?

You could use exists:
select t.*
from mytable t
where exists (
select 1 from mytable t1 where t1.comment = 'foo' and t1.group = t.group
)
For performance with this query, you want an index on (comment, group).

With the operator IN:
select * from tablename
where [Group] in (
select [Group] from tablename
where [Comment] = 'foo'
)
See the demo.
Results:
> User | Comment | Group
> ---: | :------ | :----
> 1 | foo | a
> 2 | bar | a
> 4 | 123 | a
> 6 | foo | d
> 7 | 654 | a

Related

SQL select all rows in a single row's "history"

I have a table that looks like this:
ID | PARENT_ID
--------------
0 | NULL
1 | 0
2 | NULL
3 | 1
4 | 2
5 | 4
6 | 3
Being an SQL noob, I'm not sure if I can accomplish what I would like in a single command.
What I would like is to start at row 6, and recursively follow the "history", using the PARENT_ID column to reference the ID column.
The result (in my mind) should look something like:
6|3
3|1
1|0
0|NULL
I already tried something like this:
SELECT T1.ID
FROM Table T1, Table T2
WHERE T1.ID = 6
OR T1.PARENT_ID = T2.PARENT_ID;
but that just gave me a strange result.
With a recursive cte.
If you want to start from the maximum id:
with recursive cte (id, parent_id) as (
select t.*
from (
select *
from tablename
order by id desc
limit 1
) t
union all
select t.*
from tablename t inner join cte c
on t.id = c.parent_id
)
select * from cte
See the demo.
If you want to start specifically from id = 6:
with recursive cte (id, parent_id) as (
select *
from tablename
where id = 6
union all
select t.*
from tablename t inner join cte c
on t.id = c.parent_id
)
select * from cte;
See the demo.
Results:
| id | parent_id |
| --- | --------- |
| 6 | 3 |
| 3 | 1 |
| 1 | 0 |
| 0 | |

Count missing values

I have a following table called Test:
Id | SomeId | Value
-----------------------------------------------------
019D9E52-41D1-45DF-81B6-C7CC484115A7 | 1 | 1
262640CA-65C2-4E30-8654-E187ACA1EEF4 | 1 | 1
53710AFC-4E19-4B1C-B68B-CDB713EC3D62 | 1 | 2
8FF7E77C-D04C-4961-82D9-87C2E5A1A096 | 1 | 2
-----------------------------------------------------
119D9E52-41D1-45DF-81B6-C7CC484115A7 | 2 | 1
762640CA-65C2-4E30-8654-E187ACA1EEF4 | 2 | 1
93710AFC-4E19-4B1C-B68B-CDB713EC3D62 | 2 | 2
4FF7E77C-D04C-4961-82D9-87C2E5A1A096 | 2 | 2
And there is a view called TestView:
SomeId | Value | Description
----------------------------
1 | 1 | 'One'
1 | 2 | 'Two'
1 | 3 | 'Three'
----------------------------
2 | 1 | 'One'
2 | 2 | 'Two'
These are just pseudo code examples.
I want to count all the values from the Test table (for a specific [SomeId]), and if value from the TestView (with a specific [SomeId]) is not in the Test table I just want to display 0 as count.
If I wanted to count values WHERE [Test].[SomeId] = 1, here's the expected result:
Value | Count
-----------------
One | 2
Two | 2
Three | 0
This is my query so far:
SELECT
tv.[Description] AS [Value],
COUNT(t.[Id]) - COUNT(tv.[Value]) AS [Count]
FROM [TestView] AS tv
LEFT JOIN [Test] AS t ON
t.[SomeId] = tv.[SomeId]
AND t.[Value] = tv.[Value]
WHERE
t.[SomeId] = 1
GROUP BY
tv.[Description]
But this gives me bad result... Anyways, here's the SQL Fiddle
EDIT:
This is just an addition to a Test table. What is Test table has one more foreign key Id, let's call it OtherId. Now when I use the query from the answer I won't get the result I wanted. Here's the modified query:
SELECT
t1.Description AS Value,
COUNT(t2.Value) AS Count
FROM TestView t1
LEFT JOIN test t2
ON t1.Value = t2.Value AND t1.SomeId = t2.SomeId
WHERE t1.SomeId = 1
AND t2.[OtherId] = *something* -- this is the addition
GROUP BY t1.Value, t1.Description
ORDER BY t1.Value;
Try this:
SELECT
t1.Description AS Value,
COUNT(t2.Value) AS Count
FROM TestView t1
LEFT JOIN test t2
ON t1.Value = t2.Value AND t1.SomeId = t2.SomeId
WHERE t1.SomeId = 1
GROUP BY t1.Value, t1.Description
ORDER BY t1.Value;
Demo
Below is your Solution
SELECT
tv.[Description] AS [Value],
COUNT(t.[Id]) AS [Count]
FROM [TestView] AS tv
LEFT OUTER JOIN [Test] AS t ON tv.SomeId = t.SomeId
AND t.Value = tv.value
AND t.[SomeId] = 1
GROUP BY
tv.[Description]

sql row value depending on other row value

My table looks like this:
Name | Text | GroupID
------------------------------------
A | sometext | 1
B | x | 2
C | x | 3
D | sometext2 | 1
E | x | 2
F | abc |
G | sometext3 | 1
H | x | 2
I | x | 3
GroupID 1 -> It's a header line and should not be selected
GroupID 2-... -> IT's a Subline from the above header (ID = 1) and should be selected with the text of its header line!
If there is no group id at all then the line should be selected with no text
So when selecting everything from the above table the result should be:
B sometext 2
C sometext 3
E sometext2 2
F
H sometext3 2
I sometext3 3
Does anyone have an idea how to build the select-stmt?
try this query:
select
t1.name,
case when t1.groupid is null then '' else
(select q.text from
(select rownum as counter,name,text from TableName where groupid=1)q
where
q.counter = (select max(rownum) from TableName t2 where groupid=1 and
t2.name<=t1.name))end as Text,
t1.groupid
from
TableName t1
where
(t1.groupid<>1 or t1.groupid is null);
try also this (live demo in SQLFiddle):
-- here I return the headers without subheaders - GroupId NULL
select name,
case
when GroupID is null then null
else text
end header
from t
where groupid is null
union all
-- here I return the the others
select sub.name,
head.text
from t head
inner join (
-- here I take for each sub the associated header
select t.name, max(h.name) header
from t
inner join (select t.Name, t.Text from t where groupid = 1) h
on h.name < t.name
where groupid > 1
group by t.name
) sub on head.name = sub.header
order by 1

T-sql using values from one table and displaying them in different columns

My database Table looks like:
ID | INDEX | Value |
1 | 0 | 3 |
1 | 1 | 5 |
1 | 2 | 7 |
2 | 0 | 4 |
2 | 1 | 6 |
2 | 2 | 2 |
What I want my output to look like is the difference of the values column based on their index
i.e. value(id=2,index = i) - value(id = 1, index = i) so the output table will look like
INDEX | Delta Value |
0 | 1 |
1 | 1 |
2 | -5 |
My attempt at solving this problem is as follows:
SELECT Top 6
col1.value column1,
col2.value column2,
col2.value - col1.value
FROM My_Table col1
INNER JOIN My_Table col2
ON col1.index = col2.index
WHERE col1.id = 1
OR col2.id = 2
I know there are problems with this query. But I just haven't been able to produce the output that I want. Any help is appreciated.
You can do this by join
select
t1.ind, t1.value - t2.value as delta
from My_Table as t1
inner join My_Table as t2 on t2.id = 2 and t2.ind = t1.ind
where t1.id = 1
Or by simple aggregate:
select
ind, sum(case id when 1 then 1 when 2 then -1 end * value) as delta
from My_Table
group by ind
Do you want something like this?
select
col1.value column1,
col2.value column2,
col2.value - col1.value AS delta
From My_Table col1
INNER JOIN My_Table col2
ON col1.index = col2.index
AND col2.id = 2
where col1.id = 1
have a look at mine
select t1.[index],
t2.value-t1.value
from my_table t1 inner join my_table t2
on t1.[index] = t2.[index]
where t1.id = 1 and t2.id = 2
order by t1.[index]

how to query range?

Raw Data
| ID | STATUS |
| 1 | A |
| 2 | A |
| 3 | B |
| 4 | B |
| 5 | B |
| 6 | A |
| 7 | A |
| 8 | A |
| 9 | C |
Result
| START | END |
| 1 | 2 |
| 6 | 8 |
Range of STATUS A
How to query ?
This should give you the correct ranges:
SELECT
STATUS,
MIN(ID),
max_id
FROM (
SELECT
t1.STATUS,
t1.ID,
COALESCE(MAX(t2.ID), t1.ID) max_id
FROM
yourtable t1 LEFT JOIN yourtable t2
ON t1.STATUS=t2.STATUS AND t1.ID<t2.ID
WHERE
NOT EXISTS (SELECT NULL
FROM yourtable t3
WHERE
t3.STATUS!=t1.STATUS
AND t3.ID>t1.ID AND t3.ID<t2.ID)
GROUP BY
t1.ID,
t1.STATUS
) s
WHERE
status = 'A'
GROUP BY
STATUS,
max_id
Please see fiddle here.
You are probably better off with a cursor-based solution or a client-side function.
However, if you were using Oracle - the following would work.
WITH LOWER_VALS AS
( -- All the Ids with no immediate predecessor
SELECT ROWNUM AS RN, STATUS, ID AS LOWER FROM
(
SELECT STATUS, ID
FROM RAWDATA RD1
WHERE RD1.ID -1 NOT IN
(SELECT ID FROM RAWDATA PRED_TABLE WHERE PRED_TABLE.STATUS = RD1.STATUS)
ORDER BY STATUS, ID
)
) ,
UPPER_VALS AS
( -- All the Ids with no immediate successor
SELECT ROWNUM AS RN, STATUS, ID AS UPPER FROM
(
SELECT STATUS, ID
FROM RAWDATA RD2
WHERE RD2.ID +1 NOT IN
(SELECT ID FROM RAWDATA SUCC_TABLE WHERE SUCC_TABLE.STATUS = RD2.STATUS)
ORDER BY STATUS, ID
)
)
SELECT
L.STATUS, L.LOWER, U.UPPER
FROM
LOWER_VALS L
JOIN UPPER_VALS U ON
U.RN = L.RN;
Results in the set
A 1 2
A 6 8
B 3 5
C 9 9
http://sqlfiddle.com/#!4/10184/2
There is not a lot to go on from what you put, but I think this might work. I am using T-SQL because I don't know what you are using?
SELECT
min(ID)
, max(ID)
FROM RawData
WHERE [Status] = 'A'