Group By + Left Outer Join In Sqlite - sql

I'm trying to join 2 tables (even if there's no match for the 2nd table I want to bring the results).
So I thought I can solve that problem using a LEFT OUTER JOIN, but for some reason I'm not able to do that.
Here's the schema:
entry_types table:
ID NAME
---------- ----------
1 entry_type1
2 entry_type2
entries table:
ID VALUE ENTRY_TYPE_ID DATE
---------- ---------- -------------- ----------
1 55.5 1 2016-09-18T17:46:27.398Z
2 84.21 2 2016-09-18T18:41:54.142Z
3 144.5 2 2016-09-19T01:13:51.099Z
4 150.7 1 2016-07-17T19:28:12.026Z
Looking to the schema above we can imply that I have both entry_types ocurring in September, but in July I have only one entry_type.
So, what I want?
I want to retrieve always the two entry_types, and, of course, set 0 to the inexistent entry_type (if there's one).
The following query that I'm trying is the following:
SELECT et.name as entry_type,
SUM(CASE WHEN en.value IS NULL THEN 0 ELSE en.value END) as total
FROM entries en
LEFT OUTER JOIN entry_types et
ON en.entry_type_id = et.id
WHERE STRFTIME('%m', en.date) = 'SOME MONTH'
GROUP BY en.entry_type_id
The expected result:
If I search by 'September':
NAME TOTAL
---------- ----------
entry_type1 55.5
entry_type2 228.71
If I search by 'July':
NAME TOTAL
---------- ----------
entry_type1 150.7
entry_type2 0
Thanks in advance. Any help will be appreciated.

SELECT t1.name,
COALESCE(t2.value, 0)
FROM entry_types t1
LEFT JOIN
(
SELECT entry_type_id, SUM(value) AS value
FROM entries
WHERE STRFTIME('%m', date) = 'SOME MONTH'
GROUP BY entry_type_id
) t2
ON t1.id = t2.entry_type_id

I think we can do that without using sub query
SELECT et.id,et.name AS entry_type,
CASE WHEN IFNULL(SUM(en.value), '') = '' THEN 0 ELSE SUM(en.value) AS total
FROM entry_types et
LEFT JOIN entries en ON en.entry_type_id = et.id
AND STRFTIME('%m', en.date) = 'SOME MONTH'
GROUP BY et.id,et.name

Related

DB2 SQL Result Set without Duplicates

I am trying to adjust this SQL syntax to only show one row if it has a dash number in the field or field is empty.
Select Distinct TRIM(TRANSLATE(itnbr,' ','F')),
Case When t3.dashonly Is NULL Then '' Else t3.dashonly End As dashonly
From amflib1.itmrva t1
Join webprddt1.drawmext17 t2 On t2.afctdwg = t1.uu25
Left Join webprddt1.wqmssoadn t3 On t3.itemno = t1.itnbr
Where t2.recseq = '0060' Order By 1
As is the resultset is:
00001 DASHONLY
--------------- ---------------
41031052-1
41031052-1 -1
41031052-10
41031052-11 -11
41031052-11
41031052-12
41031052-12 -12
41031052-13
41031052-14
41031052-15
41031052-17
Desired resultset:
00001 DASHONLY
--------------- ---------------
41031052-1 -1
41031052-10
41031052-11 -11
41031052-12 -12
41031052-13
41031052-14
41031052-15
41031052-17
Thought I don't have test data to test your query, the query below should work.
You can use ROW_NUMBER() to sort the rows in each subgroup according to a sorting criteria, and then just pick the first one per group.
select *
from (
select
TRIM(TRANSLATE(itnbr,' ','F')),
case when t3.dashonly is null then '' else t3.dashonly end As dashonly,
row_number() over(partition by TRIM(TRANSLATE(itnbr,' ','F'))
order by case when t3.dashonly is null then 0 else 1 end) as rn
from amflib1.itmrva t1
join webprddt1.drawmext17 t2 on t2.afctdwg = t1.uu25
left join webprddt1.wqmssoadn t3 on t3.itemno = t1.itnbr
where t2.recseq = '0060'
) x
where rn = 1
order by 1

SQL - Get per column count of differences when comparing two tables

I have 2 similar tables as shown below with minor difference between some cells
Table A
Roll_ID
FirstName
LastName
Age
1
AAA
XXX
31
2
BBB
YYY
32
3
CCC
ZZZ
33
Table B
Roll_ID
FirstName
LastName
Age
1
AAA
XXX
35
2
PPP
YYY
36
3
QQQ
WWW
37
I would like to get an output that shows the count of different records on a per-column level.
For example the output of the query for the above scenario should be
Output
Roll_ID
FirstName
LastName
Age
0
2
1
3
For this question we can assume that there will always be one column which will have non-null unique values (or one column which may be primary key). In above example Roll_ID is such a column.
My question is: What would be the most efficient way to get such an output? Is there anything to keep in mind when running such query for tables that may have millions of records from point of view of efficiency?
First you have to join the tables
SELECT *
FROM table1
JOIN table2 on table1.ROLL_ID = table2.ROLL_ID
Now just add the counts
SELECT
SUM(CASE WHEN table1.FirstName <> table2.FirstName THEN 1 ELSE 0 END) as FirstNameDiff,
SUM(CASE WHEN table1.LastName <> table2.LastName THEN 1 ELSE 0 END) as LastNameDiff,
SUM(CASE WHEN table1.Age <> table2.Age THEN 1 ELSE 0 END) as AgeDiff
FROM table1
JOIN table2 on table1.ROLL_ID = table2.ROLL_ID
If an id not existing in both tables is considered "different" then you would need something like this
SELECT
SUM(CASE WHEN COALESCE(table1.FirstName,'x') <> COALESCE(table2.FirstName,'y') THEN 1 ELSE 0 END) as FirstNameDiff,
SUM(CASE WHEN COALESCE(table1.LastName,'x') <> COALESCE(table2.LastName,'y') THEN 1 ELSE 0 END) as LastNameDiff,
SUM(CASE WHEN COALESCE(table1.Age,-1) <> COALESCE(table2.Age,-2) THEN 1 ELSE 0 END) as AgeDiff
FROM ( SELECT table1.Roll_id FROM table1
UNION
SELECT table2.Roll_id FROM table2
) base
LEFT JOIN table1 on table1.ROLL_ID = base.ROLL_ID
LEFT JOIN table2 on table2.ROLL_ID = base.ROLL_ID
Here we get all the roll_ids and then left join back to the tables. This is much better than a cross join if the roll_id column is indexed.
SELECT SUM(IIF(ISNULL(A.FirstName, '') <> ISNULL(B.FirstName, ''), 1, 0)) AS FirstNameRecordDiff,
SUM(IIF(ISNULL(A.LastName, '') <> ISNULL(B.LastName, ''), 1, 0)) AS LastNameRecordDiff,
SUM(IIF(ISNULL(A.Age, 0) <> ISNULL(B.Age, 0), 1, 0)) AS LastNameRecordDiff
FROM A
FULL OUTER JOIN B
ON B.Roll_ID = A.Roll_ID;
This query intentionally allows nulls to equal, assuming that a lack of data would mean the same thing to the end user.
As written, it would only work on SQL Server. To use it for MySQL or Oracle, the query would vary.

Trying to look up records based on a join

I'm trying to work on a stored procedure that is somewhat tricky, let's say I have Table_1 with this data:
Num1 Name1 Code1 Desc
-------------------------------------------
123B Apple 10 Text1
123B Apple 11 Text1
123C Google 20 Text2
I also have a lookup table that looks like this:
Tbl_LookUp
Num1 Code1
-------------------
123B 10
123C 25
So what I am trying to do in this scenario is:
Select data from Table_1 WHERE:
There is a match between Table_1 and Tbl_Lookup on Num1
and
If there is a more than 1 record for a particular Num1 in Table_1, then only return the row where Table_1.Code1=Tbl_Lookup.Code1
Otherwise, if there is only 1 record for a particular Num1 in Table_1, then even if the Table_1.Code1 = Tbl_Lookup.Code1 does not work, still return the record.
Desired end result:
Num1 Name1 Code1 Desc
--------------------------------------------
123B Apple 10 Text1
123C Google 20 Text2
123B is returned because there are multiple records for this Num1. One of them has the Code1 that corresponds to Tbl_Lookup.Code1
123C is returned, because although the Code1 does not match Tbl_Lookup, there is only one record, so in that case join doesn't matter, and we still want to return it.
Any help is greatly appreciated.
Not sure if there is a better way to do this. But this should give you want you are looking for
select t.*
from table1 t
join Tbl_LookUp l on l.Num1 = t.Num1
where t.code1 = l.code1
or exists ( select count(1) from table1 i
where i.Num1= t.Num1
group by Num1
having count(Num1) = 1 )
One way is
select t.Num1, t.Name1, t.Code1, t.Desc
from (
select Num1, Name1, Code1, Desc,
count(code1) over(partition by Num1) cnt
from Table_1 ) t
join Tbl_Lookup tl on t.Num1 = tl.Num1
and (t.cnt = 1 or t.Code1 = tl.Code1)
This is a great place to use apply:
select t1.*
from tbl_lookup l cross apply
(select top (1) t1.*
from table1 t1
where t1.num1 = l.num1
order by (case when t.code = l.code1 then 1 else 2 end)
);
Yet another way to obtain the desired results - identify exact lookup matches with exists and count occurences of num1, then allow any with a count of 1 or only matches on both columns where more than 1:
select num1, name1, code1, [desc]
from (
select * , case when exists (select * from [lookup] l where l.num1 = t.num1 and l.code1 = t.code1) then 1 end lmatch, Count(*) over (partition by num1) cnt
from t1 t
where exists (select * from [lookup] l where l.num1 = t.num1)
)x
where lmatch = 1 and cnt > 1 or cnt = 1;

Get single row depending of conditional

I have a simple select query with some joins like:
SELECT
[c].[column1]
, [c].[column2]
FROM [Customer] AS [c]
INNER JOIN ...
So I do a left join with my principal table as:
LEFT JOIN [Communication] AS [com] ON [c].[CustomerGuid] = [com].[ComGuid]
this relatioship its 1 to *, one customer can have multiple communications
So in my select I want to get value 1 or 2 depending of condition:
Condition:
if ComTypeKey (from communication) table have a row with value 3 and have another row with vale 4 return 1 then 0
So I try something like:
SELECT
[c].[column1]
, [c].[column2]
, IIF([com].[ComTypeKey] = 3 AND [com].[ComTypeKey] = 4,1,0)
FROM [Customer] AS [c]
INNER JOIN ...
LEFT JOIN [Communication] AS [com] ON [c].[CustomerGuid] = [com].[ComGuid]
But it throws me two rows, beacause there are 2 rows on communication. My desire value is to get only one row with value 1 if my condition is true
If you have multiple rows you need GROUP BY, then count the relevant keys and subtract 1 to get (1, 0)
SELECT
[c].[column1]
, [c].[column2]
, COUNT(CASE WHEN [ComTypeKey] IN (3,4) THEN 1 END) - 1 as FLAG_CONDITION
FROM [Customer] AS [c]
INNER JOIN ...
LEFT JOIN [Communication] AS [com]
ON [c].[CustomerGuid] = [com].[ComGuid]
GROUP BY
[c].[column1]
, [c].[column2]
I'm not really sure I understand.
This will literally find if both values 3 and 4 exist for that CustomerGuid, and only select one of them in that case - not filtering out any record otherwise.
If this is not what you want, providing sample data with the expected result would remove the ambiguity.
SELECT Field1,
Field2,
...
FieldN
FROM (SELECT TMP.*,
CASE WHEN hasBothValues = 1 THEN
ROW_NUMBER() OVER ( PARTITION BY CustomerGuid ORDER BY 1 )
ELSE 1
END AS iterim_rn
FROM (SELECT TD.*,
MAX(CASE WHEN Value1 = '3' THEN 1 ELSE 0 END) OVER
( PARTITION BY CustomerGuid ) *
MAX(CASE WHEN Value1 = '4' THEN 1 ELSE 0 END) OVER
( PARTITION BY CustomerGuid ) AS hasBothValues
FROM TEST_DATA TD
) TMP
) TMP2
WHERE interim_rn = 1

SQL IN or EXISTS clause issue

I have two separate queries that I'd like to combine but I'm struggling to get the result I'd like. One summarizes all the values in the table and another selects duplicate rows based on the most recent date.
A shortened version of the first query is:
SELECT a.PLANT_NO "PlantNumber",
SUM(CASE WHEN a.REC_STATUS_CD = 'RR' THEN -a.KW_CTR_REDELIVERED_HV
ELSE a.KW_CTR_REDELIVERED_HV END) "KeepWholeResidueMMBtu",
SUM(a.ETH_APPLIED_POP_PCT + a.ISO_APPLIED_POP_PCT +
(CASE WHEN a.PLANT_NO = '002' THEN a.ALTLIQ_APPLIED_POP_PCT ELSE 0 END)
)/100 "NGLPOPPaymentPercent"
FROM GAS_STMT a
INNER JOIN SETTLE_SUMMARY c
ON CASE WHEN SUBSTR(a.TRNX_ID,1,1) = '-'
THEN SUBSTR(a.TRNX_ID, 2, LENGTH(a.TRNX_ID))
ELSE CAST(a.TRNX_ID AS VARCHAR2(100))
END = c.TRNX_ID
AND a.MTR_NO||a.MTR_SFX = c.MTR_NO||c.MTR_SFX
WHERE TO_CHAR(a.PROD_DT, 'YYYY') >= TO_CHAR(ADD_MONTHS(SYSDATE, -36), 'YYYY')
AND a.STATUS_UNIT_TM_CD = 'M'
GROUP BY a.PLANT_NO
ORDER BY a.PLANT_NO
The other query is used to filter out four transactions based on the most recent transaction date.
SELECT a.*
FROM GAS_STMT a,
(SELECT MTR_NO,MTR_SFX,TRNX_ID,REC_STATUS_CD,MAX(ACCT_DT) ACCT_DT
FROM GAS_STMT
WHERE REC_STATUS_CD = 'RR'
GROUP BY MTR_NO, MTR_SFX, TRNX_ID, REC_STATUS_CD
HAVING COUNT(TRNX_ID) > 1) b
WHERE a.MTR_NO = b.MTR_NO
AND a.TRNX_ID = b.TRNX_ID AND a.REC_STATUS_CD = b.REC_STATUS_CD
AND a.ACCT_DT = b.ACCT_DT
I would think that I could use where NOT IN or NOT EXISTS to have the first query sum everything except for those four records excluded in the second query.
Using EXISTS I get the same result as the first query by itself and using NOT EXISTS I get no results. When I use IN I get a sum of the excluded records which is the opposite of what I want.
Is there a good way to do this in PL/SQL? I'm confused that I'm not getting any records for the NOT EXISTS query.
Example of first query results:
Plant_No - Sum
002 - 100
450 - 50
500 - 50
Example of second query results:
Trnx_ID - Plant_no - KW_CTR_REDELIVERED_HV
1234 - 002 - -.99
1235 - 002 - -.99
Intended result:
Plant_No - Sum
002 - 98.02
450 - 50
500 - 50
If you want to exclude the records returned by the second query, try:
SELECT a.PLANT_NO "PlantNumber",
SUM(CASE WHEN a.REC_STATUS_CD = 'RR' THEN -a.KW_CTR_REDELIVERED_HV
ELSE a.KW_CTR_REDELIVERED_HV END) "KeepWholeResidueMMBtu",
SUM(a.ETH_APPLIED_POP_PCT + a.ISO_APPLIED_POP_PCT +
(CASE WHEN a.PLANT_NO = '002' THEN a.ALTLIQ_APPLIED_POP_PCT ELSE 0 END)
)/100 "NGLPOPPaymentPercent"
FROM GAS_STMT a
INNER JOIN SETTLE_SUMMARY c
ON CASE WHEN SUBSTR(a.TRNX_ID,1,1) = '-'
THEN SUBSTR(a.TRNX_ID, 2, LENGTH(a.TRNX_ID))
ELSE CAST(a.TRNX_ID AS VARCHAR2(100))
END = c.TRNX_ID
AND a.MTR_NO||a.MTR_SFX = c.MTR_NO||c.MTR_SFX
LEFT JOIN (SELECT MTR_NO,MTR_SFX,TRNX_ID,REC_STATUS_CD,MAX(ACCT_DT) ACCT_DT
FROM GAS_STMT
WHERE REC_STATUS_CD = 'RR'
GROUP BY MTR_NO, MTR_SFX, TRNX_ID, REC_STATUS_CD
HAVING COUNT(TRNX_ID) > 1) b
ON a.MTR_NO = b.MTR_NO
AND a.TRNX_ID = b.TRNX_ID
AND a.REC_STATUS_CD = b.REC_STATUS_CD
AND a.ACCT_DT = b.ACCT_DT
WHERE TO_CHAR(a.PROD_DT, 'YYYY') >= TO_CHAR(ADD_MONTHS(SYSDATE, -36), 'YYYY')
AND a.STATUS_UNIT_TM_CD = 'M'
AND b.MTR_NO IS NULL
GROUP BY a.PLANT_NO
ORDER BY a.PLANT_NO
Join b from the second query on to the first query the same way that the second query does it i.e.
inner join (SELECT MTR_NO,MTR_SFX,TRNX_ID,REC_STATUS_CD,MAX(ACCT_DT) ACCT_DT
FROM GAS_STMT
WHERE REC_STATUS_CD = 'RR'
GROUP BY MTR_NO, MTR_SFX, TRNX_ID, REC_STATUS_CD
HAVING COUNT(TRNX_ID) > 1) b
on a.MTR_NO = b.MTR_NO
AND a.TRNX_ID = b.TRNX_ID AND a.REC_STATUS_CD = b.REC_STATUS_CD
AND a.ACCT_DT = b.ACCT_DT
that way you get everything from the first query but only from the rows that would show up on the second query