Joining data when one table has null value - sql

I have two tables, and I join them together on the date column. This works great besides when one table are missing the date.
I.e, in table two, I don't have 10.10.2016. I would still love that line to appear in the result, since this is a day I want to show that there has been no activity.
This is for a bar: I have one table where they register the count on the beer tap, and one who keeps track of sold ones.
If they are closed one day, they don't actually sell anything, but they still want the staff to register the number of tapped beers, just in case.
The data from 10.10.2016 would be something like this then:
Table 1 (sales, not open 10.10 = no data stored at all)
Date Sold
10.08 22
10.09 31
10.11 54
Table 2 (Tapped, they count every day = have data 10.10)
Date Tapped
10.08 23
10.09 31
10.10 0
10.11 54
I want the result to show it like this:
Date Tapped Sold Diff
10.08 23 22 1
10.09 31 31 0
10.10 0 0 0
10.11 54 54 0
But I cannot get this to work, because when I join in table two, it can't connect the "sold" and "tapped" ones from 10.10 since I don't have a way to mach them.
Is there any way of doing this?

CREATE TABLE #A
(
DATE NUMERIC
(22,6),SOLD INT
)
INSERT INTO #A VALUES
(10.08,22),
(10.09,31),
(10.11,54)
CREATE TABLE #B
(
DATE NUMERIC
(22,6),TAPPED INT
)
INSERT INTO #B VALUES
(10.08,23),
(10.09,31),
(10.10,0),
(10.11,54)
SELECT A.DATE,A.TAPPED,ISNULL(B.SOLD,0)SOLD,A.TAPPED-ISNULL(B.SOLD,0) AS DIFFRENCE
FROM #B A LEFT JOIN #A B ON A.DATE=B.DATE

Use a left or right join.
Below sample shows how to use RIGHT JOIN.
SELECT t2.Date,t2.Tapped,ISNULL(t1.sold,0) sold,t2.Tapped-ISNULL(t1.sold,0) as Diff
FROM Table1 t1
RIGHT JOIN Table2 t2
ON t1.Date=t2.Date

simple statement
SELECT tapped.date as date, IFNULL(tapped.tapped,0) as tapped, IFNULL(sales.sold,0) as sold, IFNULL(tapped.tapped - sales.sold,0) as diff
FROM
tapped
LEFT OUTER JOIN sales ON sales.date = tapped.date
ORDER BY
tapped.date ASC

Related

Having a hard time building an aggregate SQL query

I am new at SQL and have a pretty good knowledge of basic stuff but I am stuck with my request.
My request gets me te following table (except for the last column on the right end side):
Team
Variable
Date
Value
Column_I_need_to_add
A
aa
2022/05/01
100
0
A
aa
2022/06/01
25
0
A
aa
2022/07/01
580
0
A
ad
2022/08/01
50
605
B
aa
2021/05/01
75
0
B
aa
2021/06/01
110
0
B
aa
2021/07/01
514
0
B
ad
2021/08/01
213
624
What I cannot turn my head around, is how to code for the last column that fills rows for the ad variable by summing values of the aa variables of the same team but only for the two months prior to the date of the ad variable.
Here is the script I have so far, that gets me the first four columns:
SELECT
team.Team,
Var.Variable,
TO_DATE(Var.Year||'-'||LPAD(Var.Month,2,'00')||'-'||'01','YYYY-MM-DD')AS Date ,
Var.value
FROM table1 as Var
join table2 as team
on Var.code=team.code
---This last join with table3 is only there to add other columns that are not relevant to this problem.
---join table3 as detail_var on Var.variable=detail_var.code_var
I was not content with the previous answer, with OUTER APPLY, as understood from further reading. So had to do a bit of further grinding and this is what I came up with (Now for Postgres 13).
It is cleaner and does the job in a conciser fashion. I've also added a FIDDLE LINK. If you want to see the previous answer please look at the edit versions.
SELECT
team.Team
,var.Variable
,var.Date
,var.value
,CASE
WHEN var.Variable='ad' THEN
(SELECT sum(value) FROM table1
WHERE
(TO_DATE(Year||'-'||LPAD(Month::varchar(2),2,'0')||'-'||'01','YYYY-MM-DD')
BETWEEN (var.Date - INTERVAL '2 month') AND var.Date)
AND Variable = 'aa'
AND code = var.code)
ELSE null
END as past2monthsValue
FROM (
-- this sub query to change Year & Month to Date Type Value
-- this Date Type Value (Date) will be used to compare dates
-- (var.Date) in the above sub-query
SELECT
code,
Variable,
TO_DATE(Year||'-'||LPAD(Month::varchar(2),2,'0')||'-'||'01','YYYY-MM-DD') AS Date,
value
FROM table1
) var
JOIN table2 AS team ON var.code=team.code

Extract only variables which is greater than other table in influxDB

I am using influxDB and I would like to extract some values which is greater than certain threshold in other table.
For example, I have two tables as shown in below.
Table A
Time value
1 15
2 25
3 9
4 22
Table B
Time threshold
1 16
2 12
3 13
4 15
Give above two tables, I would like to extract three values which is greater than first row in Table B. Therefore what I want to have is as below.
Time value
2 25
4 22
I tried it using below sql query, but it didn't give any correct result.
select * from data1 where value > (select spec from spec1 limit1);
Look forward to your feedback.
Thanks.
Integrate the condition in an inner join:
select * from tableA as a
inner join tableB as b on a.id=b.id and a.value > b.threshold
When your time column doesn't only include integer values, you have to format the time and join on a time range. Here is an example:
SQL join on time range

Aggregate columns based off the same data

I have the following query -
SELECT d.PRD_YY,
Count(*)
FROM (SELECT CARD,
Min(TXN_DT) mindt
FROM db1.dbo.tblcards
GROUP BY CARD) a
JOIN db1.dbo.tlkpdates d
ON a.MINDT = d.GREG_DT
WHERE d.PRD_YY = 2016
AND d.PRD_NBR = 5
GROUP BY d.PRD_YY
basically, this tells me how many cards from my tblcards table first appeared in a given date range that is taken from the tlkpdates table by joining on mindt from my inner query result.
what I want to do is also see how many cards showed up in that date range altogether, and not just cards whose first occurrence was in that date range.
it doesn't seem like this is possible because i'm joining greg_dt (which is just a normal Gregorian date like 6/1/2016) on the minimum date, so how could i possible join on the maximum date (most recent occurrence)?
i know i can just make another query return that same data set but i'd rather have it in the same query.
edit - what also has to be considered is that i'm going to want to group on more than just PRD_YY - there's also a period number, period week, and period day, for a more granular view.
sample data -
Card Date Store Transaction
10123131444 2014-05-08 25 141414
40999999999 2013-12-07 847 15154
30999999998 2015-02-05 96 234235
20999999997 2016-03-21 139 2342525
50999999996 2016-03-30 659 1234121515
70999999995 2016-03-04 659 52525
50999999994 2016-03-03 907 2362362
20999999993 2014-05-23 941 2623626
70999999992 2013-12-03 18 123124
40999999991 2014-01-18 107 1512515
current output
prd_yy new_cards
2016 22911
desired output
prd_yy new_cards total_cards
2016 22911 54992
Assuming that card is a PK in the tblCards table (or at least only appears once each day at most), I think this will work for what you're trying to do:
SELECT
D.prd_yy,
SUM(CASE WHEN MD.card IS NOT NULL THEN 1 ELSE 0 END) AS new_cards,
COUNT(*) AS total_cards
FROM
dbo.tlkpDates D
INNER JOIN dbo.tblCards C ON C.txn_dt = D.greg_dt
LEFT OUTER JOIN (SELECT card, MIN(txn_dt) AS min_dt FROM dbo.tblCards GROUP BY card) MD ON
MD.card = C.card AND MD.min_dt = C.txn_dt
WHERE
D.prd_yy = '2016' AND
D.prd_nbr = 5
GROUP BY
D.prd_yy
Use the LEFT OUTER JOIN on the minimum dates as a flag for whether or not that particular day is the "first". Then you can use that with SUM(CASE...) to get your conditional count.

Pivot results not working for me

I have the following query that generates my pivot results:
SELECT * FROM
(
SELECT
#tmp1.Name,
DATEDIFF(D,#tmp1.AuthDate,#tmp1.AuthExpirationDate) AS AuthLenInDays,
#tmp1.NbrOfAuthorizations,
#tmp1.MODE
FROM #tmp1
LEFT JOIN #tmp2
ON #tmp2.AuthID = #tmp1.AuthID
GROUP BY #tmp1.Name, #tmp1.NbrOfAuthorizations, #tmp1.AuthDate, #tmp1.AuthExpirationDate, #tmp1.MODE
) AS InnerTbl
PIVOT
(AVG(AuthLenInDays) FOR [MODE] IN ([Preservation])
) PivotResults1
The results are as follows:
Name NbrOfAuthorizations Preservation
Centro 1 79
Dennis 1 92
Therapy Center 1 68
Florez 1 92
I have two problems that I have not been able to figure out, I've tried everything I can think of and even other suggestions from stackoverflow.
I can't figure out how to change the name of the right-most column (Preservation)
in my results. It's an average number so I'd like to label that
column 'Average'.
Also, the NbrOfAuthorizations needs to be summed for all the values
in the table. I have tried using a pivot and this gets me close but
not all the way there, I have also tried using a SUM in the InnerTbl
query but that isn't it either.
If I take my raw data and export that to excel and do a pivot there, I can see the numbers and what I should be getting. I am trying to take that process and do it purely in SQL. Based on the data in the table, the values for the SUM should be
Name NbrOfAuthorizations Preservation
Centro 5 79
Dennis 1 92
Therapy Center 57 68
Florez 1 92
Any masters of pivot out there?
Looks like you don't need pivot at all:
select
t1.Name,
sum(t1.NbrOfAuthorizations) as NbrOfAuthorizations,
avg(datediff(dd, t1.AuthDate, t1.AuthExpirationDate)) as AuthLenInDays
from #tmp1 as t1
-- looks like you don't need join also, or there're multiple rows
-- in #tmp2 for row in #tmp1
-- left outer join #tmp2 as t2 on t2.AuthID = t1.AuthID
where t1.mode = 'Preservation'
group by t1.Name

Need to repeat and calculate values in a single Select statement

I hope that someone can help me with my issue. I need to create in a single SELECT statement (the system that we use has some pivot tables in Excel that handle one single SELECT) the following:
I have a INL (Invoice Lines) table, that has a lot of fields, but the important one is the date.
INL_ID DATE
19 2004-03-15 00:00:00.000
20 2004-03-15 00:00:00.000
21 2004-03-15 00:00:00.000
22 2004-03-16 00:00:00.000
23 2004-03-16 00:00:00.000
24 2004-03-16 00:00:00.000
Now, I also have a ILD (Invoice Line Details) that are related by an ID field to the INL table. From the second table I will need to use the scu_qty field to "repeat" values from the first one in my results sheet.
The ILD table values that we need are:
INL_ID scu_qty
19 1
20 1
21 1
22 4
23 4
Now, with the scu_qty I need to repeat the value of the first table and also add one day each record, the scu_qty is the quantity of days of the services that we sell in the ILD table.
So I need to get something like (i'm going to show the INL_ID 22 that you can see has a value different of 1 in the SCU_QTY). The results of the select has to give me something like:
INL_ID DATE
22 2004-03-15 0:00:00
22 2004-03-16 0:00:00
22 2004-03-17 0:00:00
22 2004-03-18 0:00:00
In this information I only wrote the fields that need to be repeated and calculated, of course I will need more fields, but will be repeated from the INL table, so I don't put them so you don't get confused.
I hope that someone can help me with this, it's very important for us this report. Thanks a lot in advance
(Sorry for my English, that isn't my first language)
SELECT INL_ID, scu_qty, CalculatedDATE ...
FROM INL
INNER JOIN ILD ON ...
INNER JOIN SequenceTable ON SequenceTable.seqNo <= ILD.scu_qty
ORDER BY INL_ID, SequenceTable.seqNo
Depending on your SQL flavour you will need to lookup date manipulation functions to do
CalculatedDATE = {INL.DATE + SequenceTable.seqNo (days)}
select INL.INL_ID, `DATE`
from
INL
inner join
ILD on INL.INL_ID = ILD.INL_ID
inner join (
select 1 as qty union select 2 union select 3 union select 4
) s on s.qty <= ILD.scu_qty
order by INL.INL_ID
In instead of that subselect you will need a table if quantity is a bit bigger. Or tell what is your RDBMS and there can be an easier way.