Counting the rows of multiple distinct columns - sql

I'm trying to count the number of rows that have distinct values in both of the columns "a" and "b" in my Sybase ISQL 9 database.
What I means is, the following dataset will produce the answer "4":
a b
1 9
2 9
3 8
3 7
2 9
3 7
Something like the following syntax would be nice:
SELECT COUNT(DISTINCT a, b) FROM MyTable
But this doesn't work.
I do have a solution:
SELECT COUNT(*) FROM
(SELECT a, b
FROM MyTable
WHERE c = 'foo'
GROUP BY a, b) SubTable
But I was wondering if there is a neater way of constructing this query?

How about:
SELECT COUNT(*)
FROM (SELECT DISTINCT a, b FROM MyTable)
For more information on why this can't be done in a simpler way (besides concatenating strings as noted in a different answer), you can refer to the this Google Answers post: Sql Distinct Count.

You could concatenate a and b together into 1 string like this (TSQL, hopefully something very similar in Sybase:
SELECT COUNT(DISTINCT(STR(a) + ',' + STR(b)))
FROM #YourTable

Related

calculating average metric across two tables in Postgres SQL

I currently have two tables, A and B, where
Table A:-
col1 col2
a 1,2,3
b 1,4,5
c 4
Table B:-
ID metric 1
1 231.0
2 1123.1
3 110
4 1231
5 116
I have to find the mean value of metric 1 for each col1 value in Table A. The resulting table should contain col1 in descending order measured by avg(metric1) value from table B, using SQL
Result: -
col1 avg(metric1) count
c 1231 1
b 526 3
c 488 3
any ideas on how I can come up with a query for the same in Postgres SQL? I've tried the following query, but this does not work :
combined_stats AS(
select avg(metric1), count(*)
from table_b
where ID in (select col2 from table_a)
group by (select col1 from table_a)
Fix your data model! Do not store numbers in strings! Do not store multiple values in a string!
Let me assume that you are stuck with someone else's really bad data model. If so, you can split the results and join:
select a.col1, avg(b.metric1), count(b.id)
from a left join
b
on b.id = any (regexp_split_to_array(col2, ','))
group by a.col1;
Note: If b.id is a number, then you need to deal with type conversions, something like:
on b.id::text = any (regexp_split_to_array(col2, ','))
Here is a db<>fiddle.

Why does this sql snippet return 8 or 1 always?

What is the result of:
WITH Tbl AS (SELECT 5 AS A UNION SELECT 6 AS A)
SELECT COUNT(*) AS Tbl FROM Tbl AS A, Tbl AS B, Tbl AS C;
I know the result is supposed to be 8 but I don't know why. Also when I change both values (the 5 or 6) to the same thing it returns a table with the value 1 instead of 8 but all other instances it returns 8 no matter what numbers if they are different. I tested it out with an online sql executor.
Here is what the query does:
the common table expression (the subquery within the with clause) generates a derived table made of two rows
then, in the outer query, the from clause generates a cartesian product of this resultset twice: that's a total of 8 rows (2 * 2 * 2)
the select clause counts the number of rows - that's 8
The content of the rows in the with clause does not matter: this 5 and 6 could very well be foo and bar, or null and null, the result would be the same.
What makes a difference is the number of rows that the with clause generates. If it was generating just one row, you would get 1 as a result (1 * 1 * 1). If it was generating 3 rows, you would get 27 - and so on.
This expression:
WITH Tbl AS (SELECT 5 AS A UNION SELECT 6 AS A)
creates a (derived) table with two rows.
This expression:
WITH Tbl AS (SELECT 5 AS A UNION SELECT 5 AS A)
creates a (derived) table with one row, because UNION removes duplicates.
The rest of the query just counts the number of rows in the 3-way Cartesian product, which is either 111 or 222.

columns to rows change in oracle sql

I have columns a,b in table x.And i want to change this columns data into rows.
it is possible to have duplicate vales in table but in columns to row change only distinct values should come.
E.G:
a b
1 2
1 11
3 4
5 6
7 8
9 10
......etc
the result 1 (query 1) should be 1-2,1-11,3-4,5-6,7-8,9-10.....etc
The result 2 (query 2) should b 1,3,5,7,9....etc(only one 1 must come as we have duplicate data for column a)
how can i achieve this in oracle SQL.
Please help.
For Oracle 11 use function listagg() and in first query concatenate columns, in second - select distinct values at first.
Query 1:
select listagg(a||'-'||b, ',') within group (order by a, b) result from t
RESULT
------------------------------
1-2,1-11,3-4,5-6,7-8,9-10
Query 2:
select listagg(a, ',') within group (order by a) result
from (select distinct a from t)
RESULT
------------------------------
1,3,5,7,9
For older versions you can use wmsys.wm_concat.

SQL "IN" statement for multiple columns

I would like to filter Name,X combinations for which is never X=Y
Let's assume the following table:
*Name* *X* *Y*
A 2 1
A 2 2 <--- fulfills requirement for Name=A, X=2
A 10 1
A 10 2
B 3 1
B 3 3 <--- fulfills requirement for Name=B, X=3
B 1 1 <--- fulfills requirement for Name=B, X=1
B 1 3
So I would like to return the combination Name=A, X=10 for which X=Y is never true.
This was my approach (which is syntactically incorrect)
SELECT *
FROM TABLE
WHERE NAME
, X NOT IN (SELECT DISTINCT NAME
, X
FROM TABLE
WHERE X=Y)
My problem is the where statement which cannot handle multiple columns. Does anyone know how to do this?
Just put the columns into parentheses
SELECT *
FROM TABLE
WHERE (NAME, X) NOT IN (SELECT NAME, X
FROM TABLE WHERE X=Y);
The above is ANSI standard SQL but not all DBMS support this syntax though.
A distinct is not necessary for a sub-query for IN or NOT IN.
However NOT EXISTS with a co-related sub-query is very often faster that an NOT IN condition.
I use this on SQL Server
SELECT *
FROM TABLE
WHERE (SELECT NAME + ';' + X)
NOT IN (SELECT NAME + ';' + X
FROM TABLE WHERE X = Y);
I think you can use two condition to achieve this
SELECT *
FROM TABLE
WHERE NAME NOT IN(
SELECT a.NAME FROM TABLE a WHERE a.X=a.Y
) AND X NOT IN (
SELECT b.X FROM TABLE b WHERE b.X=b.Y
)
SELECT *
FROM TABLE T
WHERE NOT EXISTS (SELECT NAME
,X
FROM TABLE t2
WHERE t1.Name=t2.Name
AND t1.X=t2.Y)
This will check if there is such a record

SQL Query to find which group does not have a given value

I am using T-SQL.
Say if I have the following
Value Nbr
----- ---
one 6
one 7
one 8
two 6
two 7
three 5
three 3
three 2
In the above table, I need to find which group does not have 6 in it.
In this case, it is three as it does not have 6 in it.
What would be the best approach to do this?
I tried:
select Value from tbl1
where nbr <> 6
group by Value
but did not get the intended result.
select distinct value
from tbl1
where value not in
(
select distinct value
from tbl1
where nbr = 6
)