SQLite Count() and Group By not getting the count of rows - sql

I've written my SQLite query a couple different ways: 1 with a Group By and Count(), the other with a nested select that does a count().
Here's the current version:
Select t.A,
t.B,
(Select Count(*) As CurrentCount From tableB b Where b.B = t.B) As CurrentCount
From tableA t
Why does this not work in SQLite, but it's working just fine (both versions actually, the other using a group by) in SQL Server/T-SQL? Is it because of the join in the sub/nested select?
Edit: Let me clarify, I'm getting 0 for a count every time...
Edit2: I tried taking out the where clause in my nested select and it still returns 0 even though I know the table has records (133 to be exact)
Edit (Final Solution): This was NOT a code issue, it was a data issue. It's nothing that anyone would have caught. My "refresh" script that was reading the records from SQL Server was reading all 133, but the actual insert into my SQLite database had a missing comma, therefore the table WAS empty, hence the 0 records. Sorry for wasting everyone's time.

Something like
Select t.A
,t.B
,b.CurrentCount
From tableA t
INNER JOIN (Select B, Count(*) [CurrentCount] From tableB b GROUP BY B) as B
ON b.B = t.B

Related

Can I select several tables in the same WITH query?

I have a long query with a with structure. At the end of it, I'd like to output two tables. Is this possible?
(The tables and queries are in snowflake SQL by the way.)
The code looks like this:
with table_a as (
select id,
product_a
from x.x ),
table_b as (
select id,
product_b
from x.y ),
table_c as (
..... many more alias tables and subqueries here .....
)
select * from table_g where z = 3 ;
But for the very last row, I'd like to query table_g twice, once with z = 3 and once with another condition, so I get two tables as the result. Is there a way of doing that (ending with two queries rather than just one) or do I have to re-run the whole code for each table I want as output?
One query = One result set. That's just the way that RDBMS's work.
A CTE (WITH statement) is just syntactic sugar for a subquery.
For instance, a query similar to yours:
with table_a as (
select id,
product_a
from x.x ),
table_b as (
select id,
product_b
from x.y ),
table_c as (
select id,
product_c
from x.z ),
select *
from table_a
inner join table_b on table_a.id = table_b.id
inner join table_c on table_b.id = table_c.id;
Is 100% identical to:
select *
from
(select id, product_a from x.x) table_a
inner join (select id, product_b from x.y) table_b
on table_a.id = table_b.id
inner join (select id, product_c from x.z) table_c
on table_b.id = table_c.id
The CTE version doesn't give you any extra features that aren't available in the non-cte version (with the exception of a recursive cte) and the execution path will be 100% the same (EDIT: Please see Simon's answer and comment below where he notes that Snowflake may materialize the derived table defined by the CTE so that it only has to perform that step once should the CTE be referenced multiple times in the main query). As such there is still no way to get a second result set from the single query.
While they are the same syntactically, they don't have the same performance plan.
The first case can be when one of the stages in the CTE is expensive, and is reused via other CTE's or join to many times, under Snowflake, use them as a CTE I have witness it running the "expensive" part only a single time, which can be good so for example like this.
WITH expensive_select AS (
SELECT a.a, b.b, c.c
FROM table_a AS a
JOIN table_b AS b
JOIN table_c AS c
WHERE complex_filters
), do_some_thing_with_results AS (
SELECT stuff
FROM expensive_select
WHERE filters_1
), do_some_agregation AS (
SELECT a, SUM(b) as sum_b
FROM expensive_select
WHERE filters_2
)
SELECT a.a
,a.b
,b.stuff
,c.sum_b
FROM expensive_select AS a
LEFT JOIN do_some_thing_with_results AS b ON a.a = b.a
LEFT JOIN do_some_agregation AS c ON a.a = b.a;
This was originally unrolled, and the expensive part was some VIEWS that the date range filter that was applied at the top level were not getting pushed down (due to window functions) so resulted in full table scans, multiple times. Where pushing them into the CTE the cost was paid once. (In our case putting date range filters in the CTE made Snowflake notice the filters and push them down into the view, and things can change, a few weeks later the original code ran as good as the modified, so they "fixed" something)
In other cases, like this the different paths that used the CTE use smaller sub-sets of the results, so using the CTE reduced the remote IO so improved performance, there then was more stalls in the execution plan.
I also use CTEs like this to make the code easier to read, but giving the CTE a meaningful name, but the aliasing it to something short, for use. Really love that.

Removing duplicate records from JOIN in MS Access

My co-worker asked me for help with a query in MS Access that joins three tables. I have confirmed that the order and inner/outer status of the JOIN is what my co-worker wants. (They have three tables, A, B, and C; they want all records from table B plus the matching records from A and C.)
The (sanitized) query is:
SELECT B.ID, B.Date from (A RIGHT JOIN B on A.ID = B.ID) LEFT JOIN C on B.ID = C.ID
GROUP BY B.ID, B.Date
This returns the correct number of rows (about 16000). However, when I change the select and group clauses to
SELECT B.ID, B.Date, A.Time ...
GROUP BY B.ID, B.Date, A.Time
then the query returns duplicate records (the record count is about 19000). How do I improve the query to eliminate the duplicates?
This Stack Overflow answer helped me figure out the GROUP BY clause for table B. I had tried the clause as just GROUP BY B.ID, but got an error message that I hadn't done any aggregation with B.Date.
Is it actually producing duplicate records, or is it now returning multiple records from the same date that have different times? If so, you will need to assess if these are actually duplicate records for your report purpose. If they are, you will want to aggregate the time with something like min(a.time) or max(a.time) in the select clause (to get the earliest or latest instance only) and leave it out of the group by.

EXCEPT keyword in Oracle

I'm trying to use the EXCEPT keyword in Oracle 10.1.0.2.0, but kept getting error 'Unknown Command'. I've tried googling around and someone said the keyword is MINUS, so I used MINUS, instead, but I still got the same error.
Any idea?
Thanks.
So here's my query.
I'm finding the name of students who enrolls in ALL courses with course number > 500
SELECT s.name
FROM Students s
WHERE NOT EXISTS
(
SELECT c.id
FROM Courses c
WHERE c.number > 500
MINUS
SELECT e.course_id
FROM Enrollment e
WHERE e.student_id = s.id
);
Oracle MINUS is an operator; it's equivalent to EXCEPT in SQL Server. Here is a previous post explaining the difference. Here's a trivial example:
SELECT a, b, c
FROM table_a
MINUS
SELECT a, b, c
FROM table_b
If you still have problems, add the complete query you are using to your question; it's likely a simple syntax error.
Oracle 20c will support EXCEPT/EXCEPT ALL keywords.
SELECT col1, col2
FROM t1
EXCEPT
SELECT col1, col2
FROM t2;
or EXCEPT ALL if you want to handle duplicates:
SELECT col1, col2
FROM t1
EXCEPT ALL
SELECT col1, col2
FROM t2;
4.6 Set Operators
Set operators combine the results of two component queries into a single result.
EXCEPT All distinct rows selected by the first query but not the second
EXCEPT ALL All rows selected by the first query but not the second including duplicates

Weird SQL request(Join)

Assuming there are two tables A={a,b} and B={0,1,2}, which can be joined
tableA tableB
a 0
b 1
a 2
3
How to get the following result
ExpectingResult:
tableA tableB
a-------0
b-------1
null----2
null----3
OR
tableA tableB
a-------2
b-------3
null----0
null----1
Just make sure the element in each table just appear once, I tried all kinds of join(inner, full, cross), none of them can achieve so. Could anybody give me a tip?
Thank you very much
Please check this link out to the question itself: http://www.sqlfiddle.com/#!3/9fc21/2
That is a crappy request. There is almost negligible reasons for producing such an output that comes to mind, although I'm not ruling out a sane reason completely.
For SQL Server 2000, you will need to go through temp tables to get a sequential key to zip up with.
SELECT IDENTITY(int,1,1) ID, Value
INTO #tblA
FROM tableA
ORDER BY Value;
SELECT IDENTITY(int,1,1) ID, Value
INTO #tblB
FROM tableB
ORDER BY Value;
SELECT A.Value, B.Value
FROM #tblA A FULL OUTER JOIN #tblB B ON A.ID = B.ID
ORDER BY Coalesce(A.ID, B.ID);
Using SQL Server 2005, you can use a combination of ROW_NUMBER and a FULL OUTER JOIN to combine both results.
See SQL Fiddle
Unfortunately, SQL Server 2000 doesn't have a ROW_NUMBER function so you are kind of stuck with using temporary tables with identity fields to simulate a rownumber.
The gist of this would be to
Select your required data from tableA into #tempTableA, adding an identity field.
Repeat for tableB
Use the temptables to FULL OUTER JOIN the results

SQL query two tables with relation one-to-many

I have two tables A and Band the relation between A to B is A--->one-to-Many--->B
Normally i have one record of B for every record of A.
I am trying to write a query which would give me list of ONLY records of A which have more than ONE(MULTIPLE) record(s) in B.
I am very confused as I have only done basic sql queries and this one seems complex to me.
Could some one please guide me to correct answer or give me the solution.
edited:
ok i tried something like below and it gave me an error
SELECT SOME_COLUMN_NAME FROM A a, B b WHERE a.ID=b.ID and count(b.SOME_OTHER_COLUMN_NAME)>1;
ORA-00934: group function is not allowed here
I tried to search on the internet ad i am not allowed to use grouping in where clause and should go by using having. I am stuck here now.
You haven't specified which database system you are using (sql-server/mysql/sqlite/oracle etc) so this is a generic answer.
In this form, list out all the columns of A explicitly in the SELECT and GROUP BY clauses. It normally generates a good straightforward plan in most DBMS. But it can also fail miserably if the type is not GROUP-able, such as TEXT columns in SQL Server.
SELECT A.Col1, A.Col2, A.Col3
FROM A
JOIN B ON A.LinkID = B.LinkID
GROUP BY A.Col1, A.Col2, A.Col3
HAVING COUNT(*) > 1
This other form using a subquery works for any column types in A and normally produces exactly the same plan.
SELECT A.Col1, A.Col2, A.Col3
FROM A
WHERE 1 < (
SELECT COUNT(*)
FROM B
WHERE A.LinkID = B.LinkID)
You could do it with a sub-query:
select *
from A
where ( select count(*) from B where B.id = A.id ) > 1
select *
from tableA
where Id in (select IdA from tableb group by idA having COUNT(*)>1)
assuming tableB has a field called idA that links it to tableA