sql NOT with ALL operator - sql

I'm trying to use the NOT operator with ALL but does not compare as it should
I followed the following:
tablex contains for example:
+------+------+
| id | name |
+------+------+
| 6 | a |
| 7 | b |
| 8 | c |
| 9 | d |
| 10 | e |
+------+------+
5 rows in set (0.04 sec)
and tabley contains:
+------+------+
| id | name |
+------+------+
| 4 | a |
| 5 | b |
| 7 | c |
| 8 | d |
+------+------+
4 rows in set (0.03 sec)
i've used:
SELECT id, name FROM tablex WHERE NOT id < ALL (SELECT id FROM tabley);
returns:
+------+------+
| id | name |
+------+------+
| 6 | a |
| 7 | b |
| 8 | c |
| 9 | d |
| 10 | e |
+------+------+
5 rows in set (0.00 sec)
the problem is that returns lower values than those of 'tabley' in some cases,
It is very logical the solution using the operator >, but what is this about?

If you're using the < operator, it seems like you want to make sure that id is smaller than the smallest id in the subquery. So to express that in SQL:
SELECT id, name FROM tablex WHERE NOT id < (SELECT min(id) FROM tabley)
Alternately, flipping around the negation:
SELECT id, name FROM tablex WHERE id >= (SELECT min(id) FROM tabley)

Related

SQL return only rows where value exists multiple times and other value is present

I have a table like this in MS SQL SERVER
+------+------+
| ID | Cust |
+------+------+
| 1 | A |
| 1 | A |
| 1 | B |
| 1 | B |
| 2 | A |
| 2 | A |
| 2 | A |
| 2 | B |
| 3 | A |
| 3 | B |
| 3 | B |
| 3 | C |
| 3 | C |
+------+------+
I don't know the values in column "Cust" and I want to return all rows where the value of "Cust" appears multiple times and where at least one of the "ID" values is "1".
Like this:
+------+------+
| ID | Cust |
+------+------+
| 1 | A |
| 1 | A |
| 1 | B |
| 1 | B |
| 2 | A |
| 2 | A |
| 2 | A |
| 2 | B |
| 3 | A |
| 3 | B |
| 3 | B |
+------+------+
Any ideas? I can't find it.
You may use COUNT window function as the following:
SELECT ID, Cust
FROM
(
SELECT ID, Cust,
COUNT(*) OVER (PARTITION BY Cust) cn,
COUNT(CASE WHEN ID=1 THEN 1 END) OVER (PARTITION BY Cust) cn2
FROM table_name
) T
WHERE cn>1 AND cn2>0
ORDER BY ID, Cust
COUNT(*) OVER (PARTITION BY Cust) to check if the value of "Cust" appears multiple times.
COUNT(CASE WHEN ID=1 THEN 1 END) OVER (PARTITION BY Cust) to check that at least one of the "ID" values is "1".
See a demo.

How to select distinct records based on a given condition?

I have the following table in the MySQL database:
| id | col | val |
| -- | --- | --- |
| 1 | 1 | y |
| 2 | 1 | y |
| 3 | 1 | y |
| 4 | 1 | n |
| 5 | 2 | n |
| 6 | 3 | n |
| 7 | 3 | n |
| 8 | 4 | y |
| 9 | 5 | y |
| 10 | 5 | y |
Now I want to distinctly select the records where all the values of similar col are equal to y. I tried both the following queries:
SELECT DISTINCT `col` FROM `tbl` WHERE `val` = 'y'
SELECT `col` FROM `tbl` GROUP BY `col` HAVING (`val` = 'y')
But it's not working out as per my expectation. I want the result to look like this:
| col |
| --- |
| 4 |
| 5 |
But 1 is also being included in the results with my queries. Can anybody help me building the correct query? As far as I understand, I may need to create a derived table, but can't quite figure out the right path.
You are close, with the second query. Instead, compare the min and max values:
SELECT `col`
FROM `tbl`
GROUP BY `col`
HAVING MIN(val) = MAX(val) AND MIN(`val`) = 'y';
Check that 'y' is the minimum value:
HAVING MIN(val) = 'y'

Get maximum of sequence

+----+-------+
| id | value |
+----+-------+
| 1 | A |
| 2 | B |
| 3 | C |
| 4 | D |
| 5 | D |
| 6 | D |
| 7 | N |
| 8 | P |
| 9 | P |
+----+-------+
Desired output
+----+-------+---------------------+
| id | value | calc ↓ |
+----+-------+---------------------+
| 1 | A | 1 |
| 2 | B | 2 |
| 3 | C | 3 |
| 4 | D | 6 |
| 5 | D | 6 |
| 6 | D | 6 |
| 7 | N | 7 |
| 8 | P | 9 |
| 9 | P | 9 |
| 10 | D | 11 |
| 11 | D | 11 |
| 12 | Z | 12 |
+----+-------+---------------------+
Can you help me for a solution for this ? Id is identity, id must be present in output, must have the same 9 rows in output.
New note: I added rows 10,11,12. Notice that id 10 and 11 which has letter 'D' is in a different group from id 4,5,6
thanks
If the grouping also depends on the surrounding ids then this turns into something like the gaps and islands problem https://www.red-gate.com/simple-talk/sql/t-sql-programming/the-sql-of-gaps-and-islands-in-sequences/#:~:text=The%20SQL%20of%20Gaps%20and%20Islands%20in%20Sequences,...%204%20Performance%20Comparison%20of%20Gaps%20Solutions.%20
You could use the Tabibitosan method https://rwijk.blogspot.com/2014/01/tabibitosan.html
Here you also need to group by your value column but that doesn't complicate it too much:
select id, value, max(id) over (partition by value, island) calc
from (
select id, value, id - row_number() over(partition by value order by id) island
from my_table
) as sq
order by id;
The id - row_number() over(partition by value order by id) expression gives you a number which changes each time the ID value changes by more than 1 for each value of value. This gets included in the max(id) over (partition by value, island) expression. The island number is only valid for that particular value. In your case, both values N and D have a computed island number of 6 but they need to be considered differently.
Db-fiddle https://www.db-fiddle.com/f/jahP7T6xBt3cpbLRhZZdQG/1
For this sample date you need MAX() window function:
SELECT id, value,
MAX(id) OVER (PARTITION BY value) calc
FROM tablename
SELECT id, value, (SELECT max(id) FROM TABLE inner where inner.value = outer.value)
FROM table as outer

SQL Count number of column based on another column

Simple question here but I don't have any data to test with so I'm not sure if it is right.
Let's say I have a table that looks something like this:
+---------+---------+
| ColumnA | ColumnB |
+---------+---------+
| 1 | a |
| 2 | a |
| 3 | a |
| 3 | b |
| 4 | a |
| 5 | a |
| 6 | a |
| 6 | b |
| 6 | c |
| 7 | a |
+---------+---------+
I want to count the number of distinct items in column b for each column a.
So the result table would look like this:
+---------+---------+
| ColumnA | Count |
+---------+---------+
| 1 | 1 |
| 2 | 1 |
| 3 | 2 |
| 4 | 1 |
| 5 | 1 |
| 6 | 3 |
| 7 | 1 |
+---------+---------+
How would I do this?
I've been trying something like this:
dense_rank() over (partition by ColumnA order by ColumnB) count
You can use GROUP BY and COUNT with DISTINCT:
SELECT ColumnA, COUNT(DISTINCT ColumnB) AS [Count]
FROM MyTable
GROUP BY ColumnA
demo on dbfiddle.uk

Hive Find Start and End of Group or Changing point

Here is the table:
+------+------+
| Name | Time |
+------+------+
| A | 1 |
| A | 2 |
| A | 3 |
| A | 4 |
| B | 5 |
| B | 6 |
| A | 7 |
| B | 8 |
| B | 9 |
| B | 10 |
+------+------+
I want to write a query to get:
+-------+--------+-----+
| Name | Start | End |
+-------+--------+-----+
| A | 1 | 4 |
| B | 5 | 6 |
| A | 7 | 7 |
| B | 8 | 10 |
+-------+--------+-----+
Does anyone know how to do it?
This is not the most efficient way, but it this works.
SELECT name, min(time) AS start,max(time) As end
FROM (
SELECT name,time, time- DENSE_RANK() OVER (partition by name ORDER BY
time) AS diff
FROM foo
) t
GROUP BY name,diff;
I would suggest try the following query and build a GenericUDF to identify the gaps, much more easier :)
SELECT name, sort_array(collect_list(time)) FROM foo GROUP BY name;