Group and include all categories in SQL - sql

I need to select all groups in a table for each category, even if that group is missing for a given category (and put 0 or NULL as value)
I need to do this via a SQL query (Impala).
An example is reported below (basically I need to dynamically display also the last row in the second table).
Category Group Amount Category Group Amount
+--------------------------------+ +--------------------------------+
A X 1 A X 1
A Y 2 A Y 2
A Z 5 -> A Z 5
B X 2 B X 2
B Y 3 B Y 3
B Z 0
Anyone knows how to achieve this? Thanks!

You need a Cross Join of the categories and the groups first and then a Left Join:
select c.category, g.group, coalesce(amount, 0)
from
( -- all categories
select distinct Category from tab
) as c
cross join -- create all possible combinations
( -- all groups
select distinct group from tab
) as g
left join tab as a -- now join back the amount
on c.category = a.category
and g.group = a.Group

Related

Which kind of join do I need to use here?

For every row in table Y, I need a copy of the current row in Table X, taking field 1 from Table Y.
Table X
Field 1 Field 2
null A
null B
null C
Table Y
Field 1
1
2
3
Desired output
Field 1 Field 2
1 A
1 B
1 C
2 A
2 B
2 C
3 A
3 B
3 C
Looks like a cross join:
select y.field1, x.field2
from x cross join
y;
Looks like an unconditional select of both tables without matching ids
Something like
select tableY.column1, tableX.column2
from tableY, tableX
order by tableY.column1 asc, tableX.column2 asc
should do it.
BTW. Was this a school question, because then I should not have answered this.
Try this query:
SELECT #Tabley.Field1 , #TableX.Field2
FROM #TableX ,#Tabley

SQL - only select results that do not have a specific status value in a corresponding table

I have two tables, and I only want to get the Student IDs where they have perfect attendance for all months (they do not have a PerfectAttendance value of N for any month). These tables will have hundreds of millions of rows, so I was trying to come up with an approach that doesn't require a full separate subquery. If anyone has any recommendations, please let me know:
Table Student:
ID Name
------------
1 A
2 B
Table Attendance:
ID Month PerfectAttendance
---------------------------------
1 1 Y
1 2 Y
1 3 Y
1 4 Y
1 5 Y
1 6 Y
1 7 Y
1 8 Y
1 9 Y
1 10 Y
1 11 Y
1 12 Y
2 1 Y
2 2 Y
2 3 Y
2 4 Y
2 5 Y
2 6 Y
2 7 Y
2 8 Y
2 9 Y
2 10 Y
2 11 Y
2 12 N
SELECT *
FROM dbo.Student S
WHERE NOT EXISTS(SELECT 1 FROM dbo.Attendance
WHERE PerfectAttendance = 'N'
AND ID = S.ID);
My suggestion for this would be to query the table and get the number of months that each student has perfect attendance. Once you've done that, you can filter on the count being 12 (since there are twelve months).
Try this:
SELECT s.id, s.name, COUNT(*) AS numPerfectMonths
FROM student s JOIN attendence a ON s.id = a.id
WHERE a.perfectAttendance = 'Y'
GROUP BY s.id
HAVING COUNT(*) = 12;
Here is the SQL Fiddle for you.
EDIT
I made the assumption you will have 12 rows for each student. However, let's say you ran this in October and you want to see which students have a perfect attendance up to that point. You can use a subquery to pull for students without perfect attendance, and filter them out using NOT IN like so:
SELECT id
FROM student
WHERE id
NOT IN(SELECT s.id
FROM student s JOIN attendance a ON s.id = a.id
WHERE a.perfectAttendance = 'N'
GROUP BY s.id
HAVING COUNT(*) > 0);
Have an updated SQL Fiddle. To test this one, try deleting one of the rows for id number 1, and you'll still see that they are returned with perfect attendance.
Assuming you have 12 records per student in attendance table based on your data , you can do it with GROUP BY and HAVING clause.
SELECT S.ID, S.NAME
FROM Student S
JOIN Attendance A
on S.ID = A.ID
AND A.PerfectAttendance = 'Y'
GROUP BY S.ID, S.NAME
HAVING COUNT(*) = 12
I think Lamak's answer is probably the clearest and best-performing, but here is another variation on the GROUP BY method suggested by others, when you don't specifically look for a total of 12 months:
;WITH PerfectAttendance AS (
SELECT a.id
FROM Attendance a
GROUP BY a.id
HAVING MIN(a.PerfectAttendance) = 'Y'
)
SELECT s.id, s.Name
FROM PerfectAttendance p
JOIN Student s ON p.id = s.id;

SQL join tables with placing null to not existing values

I'm trying to find which market doesn't have which product according to visit date.
In order to do this I thought if I give all products to all markets there will be null dates because there will be no visit for that product for the market. To see
all products in the market I wrote a query :
SELECT id, p.ProductName FROM atb_markets
CROSS JOIN
(SELECT StokAd FROM atb_products) p
and I got this kind of a view:
MarketId productName
1 a
1 b
1 c
1 d
1 e
1 f
2 a
2 b
2 c
2 d
2 e
. .
. .
By the way these all are different tables (atb_markets, atb_products) and dates are saving on the outformmobiledata table. This table holds each record for the markets. marketId, productId and date is holding on this table (date information comes from mobile devices). Because of I need productName I need atb_products table also.
Finally I need this view by using these three tables. If I get null values I can know which products don't exists on a market.
And this is the view I need:
date MarketId productName
01.12.2013 1 a
11.12.2013 1 b
NULL 1 c
04.12.2013 1 d
20.12.2013 1 e
05.12.2013 1 f
06.12.2013 2 a
NULL 2 b
NULL 2 c
12.12.2013 2 d
NULL 2 e
. . .
. . .
**As you see in the second table market_number1 never had product c
Just use LEFT OUTER JOIN for outformmobiledata table:
SELECT d.date, m.id, p.ProductName
FROM atb_markets m
CROSS JOIN atb_products p
LEFT OUTER JOIN outformmobiledata d
ON d.marketId = m.id
AND d.productId = p.id
ORDER BY m.id, p.ProductName

Select row values that are in repeated rows that have a colum with at least 3 different values

I have a table like this
Ma Mi
-----
A b
A c
A c
A d
B b
B a
B a
B a
B a
C a
C b
I want to make a select that outputs only the "Ma" values that have at least 3 distinct "Mi" values, i've tryed group by and distinct unsuccesfully since i want to group first "Mi" and then count "Ma" with distinct "Mi".
So the intermediate step would be :
Ma Mi
-----
A b
A c
A d
B b
B a
C a
C b
So then i can count the rows per each Ma
In this case, the result would be
Ma num
------
A 3
B 2
C 2
And I could select only A because is the unique equal or higher to 3.
RESULT:
Ma num
------
A 3
Thank you in advanced !
L.
To check the results of a GROUP BY operation, you must use HAVING:
SELECT Ma,
COUNT(DISTINCT Mi) AS Num
FROM ATableLikeThis
GROUP BY Ma
HAVING COUNT(DISTINCT Mi) >= 3
Kindly find query as per your requirement:
Select Distinct MyTable.Ma,
(Select Count(Distinct MyTableAlias.Mi) From MyTable As MyTableAlias Where MyTableAlias.Ma = MyTable.Ma) As Num from MyTable WHere (Select Count(Distinct MyTableAlias.Mi) From MyTable As MyTableAlias Where MyTableAlias.Ma = MyTable.Ma) >= 3

How to find difference of two columns using in Left Outer Join in SQL Sever 2005?

I have two Tables
Let suppose A and B
Now suppose the structure of table A is Like that
id stock
37 1
40 1
37 1
40 1
37 1
37 1
And B is like that
id stock
37 1
37 1
40 1
Now i want to write a query that give me sum of specific id stock in (table A - Table B) and if that id does not exist in table B then only stock from A.
So i will expect result like that
id stock
40 1
37 2
I thought that left join will be possible option here and i write query like that
SELECT A.id,
SUM(CAST(isNull(A.Stock, 0) as int) - CAST(isNull(B.Stock, 0) as int) )'Stock'
from A
LEFT OUTER JOIN
B
ON A.id = B.id
group by A.id
But Problem is that the above query gives desired records but wrong quantity/Stocklevel as shown below:
id stock
37 0
40 1
How can I resolve Stock Level issue.
I guess you are looking for something like this.
select A.id, A.SumA - coalesce(B.SumB, 0) as stock
from (
select A.id, sum(A.stock) as SumA
from A
group by A.id
) as A
left outer join
(
select B.id, sum(B.stock) as SumB
from B
group by B.id
) as B
on A.id = B.id
Result:
id stock
----------- -----------
37 2
40 1
SE Data
SELECT A.id, A.Stock - isNull(B.stock, 0) as Stock from A
LEFT OUTER JOIN B
ON A.id = B.id
That would be it I think.
PS. you group by something that you did not include in your case scenario. Your expected result is also not understandable to me (it conflicts with your problem description)