Comparing a column against an entire table of ranges? - sql-server-2008

Sorry if this has been asked before, I've searched and have been unable to find any answers.
I have 2 tables in a DB, TableA has a column we'll call ID (a 4-digit integer), and TableB has 2 columns of 4-digit integers that form a range.
What I would like to do is check to see which ID's can be found in any range, so that if ID had
1
5
7
9,
and TableB had ranges
4-6,
100-101,
and 3000-4000, 5 would be properly matched as belonging to a range. Any ideas?

Try this:
SELECT *
FROM TableA a
WHERE EXISTS
(
SELECT 1
FROM TableB b
WHERE a.ID BETWEEN b.ID1 AND b.ID2
)

Related

SQL Distinct cannot working if having count clause

I am having trouble with my sql query (Select distinct didnt work).
My sql is :
select distinct
count(T2.Column1)
from Table1 t2
where T2.Column1='2017-05-210'
The actual Column 1 data only have 3 data,
But the output is 12
Nb :
- Column1 data is having 1 to Many situation with Column2,
Here are the actual data:
Column 1 Column 2
1 A
1 B
1 C
1 D
2 A
2 B
2 C
2 D
3 A
3 B
3 C
3 D
Can anyone help me?
Really appreciate for your attention.
Thanks!
You want to count distinct values, so do count(distinct ):
select count(distinct T2.Column1)
from Table1 t2
where T2.Column1='2017-05-210'
(However, your sample data and the query's data/columns do not match.)
Your sample data, result and query do not match.
However, what your query does is:
Find all records with a column1 = '2017-05-210'.
Count all of these records where column1 is not null (which is true for all these records, as column1 = '2017-05-210').
This results in one number (one row, one column). But you additionally say with DISTINCT that you want to remove any duplicates from your result rows. With one row only there can be no duplicates, so the function is superfluous here.
So think about what you want to count really. You count distinct values (i.e. count ignoring duplicates) with COUNT(DISTINCT column), but COUNT(DISTINCT column1) would return 1 of course, because you are only looking for one value which is '2017-05-210' (or zero in case there is no record matching this value).

Select row based on identifier and value from another row

I have a mySQL dataset that looks like this:
ID PARENT_ID VALUE
1 100 This comment should be approved
2 100 Y
3 101 Another approved comment
4 101 Y
5 102 This comment is not approved
6 102 N
I need to construct an SQL query to select the rows that have a matching parent_id and corresponding value of Y (but ignore the rows with single letters as a value in the result) to result in:
ID PARENT_ID VALUE
1 100 This comment should be approved
3 101 Another approved comment
My idea is to use GROUP BY to combine the columns, but I can't work out how to select based on the Y/N values.
There is possibly a solution here How do I select a row based on a priority value in another row? but I don't think it is asking quite the same question.
Any ideas?
Although you can express this as an aggregation, you can express this using exists:
select d.*
from dataset d
where d.value <> 'Y' and
exists (select 1
from dataset d2
where d2.parent_id = d.parent_id and d2.value = 'Y'
);
This version is probably more efficient.
First, if you possibly can, change your table schema. Your table is storing two kinds of data in the same field (yes no flags and comments). This breaks normality and will haunt you later.
But if its not your table to change, you will need to self join. Try this.
SELECT a.id, a.parent_Id, a.value
FROM table a inner join table b
ON a.parent_id =b.parent_id
WHERE a.value <> 'Y' and b.value ='Y'

What's an easy way to perform this complicated SELECT query?

Given these entries in a table table:
user entry
A 1
A 2
A 5
A 6
B 1
B 2
B 3
B 4
B 5
B 6
C 1
C 4
D 1
D 2
D 5
D 6
D 7
D 9
And we have a subset entries_A to work with, which is the array [1,2,5,6].
Problems:
Find all users that have the same entries [1,2,5,6] and more, e.g. [1,2,5,6,7] or [1,2,3,5,6].
Find all users that have a lot of the same entries (and more), e.g. [1,2,5,9] or [2,5,6,3].
The best solution to the first problem I could come up with, is the following select query:
SELECT DISTINCT user AS u FROM table WHERE EXISTS (SELECT * FROM table WHERE entry=1 AND user=u)
AND EXISTS(SELECT * FROM table WHERE entry=2 AND user=u)
AND EXISTS(SELECT * FROM table WHERE entry=5 AND user=u)
AND EXISTS(SELECT * FROM table WHERE entry=6 AND user=u)
On the other hand, I get a feeling there's some algebraic vector-problem lurking below the surface (especially for problem two) but I can't seem to wrap my head around it.
All ideas welcome!
I think the easiest way to perform this type of query is using aggregation and having. Here is an example.
To get A's that have exactly those four elements:
select user
from table
group by user
having sum(entry in (1,2,5,6)) > 0 and
count(distinct entry) = 4;
To get A's that have those four elements and perhaps others:
select user
from table
group by user
having sum(entry in (1,2,5,6)) > 0 and
count(distinct entry) >= 4;
To order users by the number of matches they have and the number of other matches:
select count(distinct case when entry in (1, 2, 5, 6) then entry end) as Matches,
count(distinct case when entry not in (1, 2, 5, 6) then entry end) as Others,
user
from table
group by user
order by Matches desc, Others;
For the first problem:
SELECT user FROM (
SELECT
DISTINCT user
FROM
table
WHERE entry IN (1,2,5,6)
) a JOIN table b ON a.user = b.user
GROUP BY a.user
HAVING COUNT(*) >= 4
For the second problem just decrease the count in the having clause.
This is how I would to your first query (though I think Gordon Linoff's answer is more efficient):
select distinct user from so s1
where not exists (
select * from so s2 where s2.entry in (1,2,5,6)
and not exists (
select * from so s3 where s2.entry = s3.entry and s1.user = s3.user
)
);
For the second problem, you would need to specify what a lot should mean... three, four, ...

MySQL Insert and merge into new Table with Rows from one Table

I have a table as follows:
id - rowid - value - date
and in each row I have:
1 - 9 - 123 - 03/2013
2 - 10 - 456 - 03/2013
I want to join both rows into one table like this:
id - rowid - value1 value2 - date
1 - 9 - 123 - 456 - 03/2013
I only need from the first table, the rowid 9 as in the example and the value and date.
From the second row I only need the value. I tried union all and multiple selection but with no success effort.
Help would be highly appreciated. Thanks in advance!
--Assumes there are ONLY 2 records in table with same date.
--If not accurate you will end up with only 1 less record per date than you currently have.
--Assumes you only what the lowest RowId recorded.
create table myNewtable as
(SELECT A.RowID, A.Value, B.Value, A.Date
FROM Oldtable A INNER JOIN Oldtable B
on A.Date=B.Date
and A.RowID < B.RowId)
--Now that we know date is date time and is likely different...
but that RowID is always +1 for the ones you want to join
create table myNewtable as
(SELECT A.RowID, A.Value, B.Value, A.Date
FROM Oldtable A
INNER JOIN Oldtable B
on A.RowID = B.RowId-1)

MySQL query returning no rows

I have two MySQL tables. What I am trying to do is to export the information where Value 1 is 1 less than Value 2 AND where ID_1 does not have its Value 1 and Value 2 equal.
Note:
Fields Value 1 and 2 are just integers.
Each distinct ID_A has the same Value_2
If there are two Value_1s that are one less than Value_2, look to Value_3 and select one that is higher
The reason why I have two tables here is because I am going to output information from both tables
We can write a script for this, but I need to do this in a single command for bonus points (which my instructor declared is possible)... I haven't even started a script for this, as I don't really know how to do that...
tableA looks like this:
ID_1 ID_2
A A
A B
B A
B B
C A
C B
C C
tableB looks like this:
ID_1 ID_2 Value_1 Value_2 Value_3
A A 2 3 NULL
A B 3 3 NULL
B A 4 5 NULL
B B 7 5 NULL
C A 7 8 98
C B 3 8 NULL
C C 7 8 56
The query should return this:
ID_1 ID_2
B A
C A
Here is what I have so far... And it keeps returning no hits, which is making me confused. I believe it is the AND clause after the first WHERE statement where I need to fix
SELECT CONCAT(...)
INTO OUTFILE '/tmp/outfile.tab'
FIELDS TERMINATED BY '\t'
ESCAPED BY ''
FROM tableA
INNER
JOIN tableB
ON tableA.ID_1 = tableB.ID_1
AND tableA.ID_2 = tableB.ID_2
WHERE tableB.Value_1 - 1 = tableB.Value_2
AND tableA.ID_1 !=
( SELECT DISTINCT
ID_1
FROM tableB
WHERE ID_1 = tableA.ID_1
AND Value_1 = Value_2
)
;
One final note: we issue all commands through putty, in which we can access MySQL
To be honest, I still don't understand exactly what you're trying to do, but I can explain why your query is returning no rows.
Look at this clause:
AND tableA.ID_1 !=
( SELECT DISTINCT
ID_1
FROM tableB
WHERE ID_1 = tableA.ID_1
AND Value_1 = Value_2
)
The subquery will necessarily always return either tableA.ID_1 or NULL. (Do you see why?) So the comparison is never "true"; it's always either "false" (because tableA.ID_1 != tableA.ID_1 is necessarily "false") or "null/indeterminate" (because tableA.ID_1 != NULL is "null/indeterminate"). Therefore, this clause filters out all results from your query — regardless of what the rest of your query might say.
I am not 100% sure of the question, but if I get it right, the first row of tableB (Line 25 in http://imgur.com/a/r3Qy5#1) should NOT be selected, because ID_1=A has Value_1=3 in the second row (Line 26 in http://imgur.com/a/r3Qy5#1), which is the same as Value_1 of the first row (Line 25 in http://imgur.com/a/r3Qy5#1).
So you could start with something like
SELECT .... FROM
tableA NATURAL JOIN tableB
WHERE Value_1=Value_2-1
AND Value_2 NOT IN (SELECT tb.Value_1 from tableB AS tb WHERE tb.ID_1=tableB.ID_1)
which fullfills requirements #1 and #2. For requirement #3 (if there are two rows for an ID_1, chose the one with the highest Value_3), we need to sort that on Value_3 and wrap it in a superquery for grouping:
SELECT .... FROM (
SELECT * FROM
tableA NATURAL JOIN tableB
WHERE Value_1=Value_2-1
AND Value_2 NOT IN (SELECT tb.Value_1 from tableB AS tb WHERE tb.ID_1=tableB.ID_1)
ORDER BY Value_3 DESC
) AS innerview
GROUP BY Value_1,Value_2
which gives the correct answer for the test data in your example.
You'll FIRST have to apply a test for your "Value_3" criteria grouped by the respective "ID_1" classification and Value1, value2. By applying the WHERE clause here, you are getting your final set of records INCLUSIVE of what WOULD be the highest value 3 entry in its result set. Now, that gets joined again to tableB AGAIN, but matching the qualifying entries. Since the COALESCE() will change any NULL value to 0 in the first result set, the JOIN clause must also match that. As in the case for the "A" and "B" groups where no Value_3 was applied, yet in the "C" group, it WILL have a valid value and pre-result in the entry with the max value of 98. That said, when re-joined back to instance "tb2" for TableB a second time will get the proper ID_2 of "A" for that set.
select
MaxQualified.ID_1,
tb2.ID_2,
MaxQualified.Value_1,
MaxQualified.Value_2,
tb2.Value_3
from
( select
tb.ID_1,
tb.Value_1,
tb.Value_2,
MAX( COALESCE( tb.Value_3, 0 ) ) as HighestVal3
from
TableB tb
where
tb.Value_1 +1 = tb.Value_2
group by
tb.ID_1,
tb.Value_1,
tb.Value_2 ) MaxQualified
JOIN TableB tb2
on MaxQualified.ID_1 = tb2.ID_1
AND MaxQualified.Value_1 = tb2.Value_1
AND MaxQualified.Value_2 = tb2.Value_2
AND MaxQualified.HighestVal3 = COALESCE( tb2.Value_3, 0 )
Now, that being said, and this is homework, this COULD fail or give multiple answers if you had multiple ID1, Value1, Value2, Value3 entries. It would return all "ID2" instances of the exact same common criteria. You would have to do even one more level nested to remove that level of distinction.
Your answer should ALSO return "A", "A", 2, 3