JOIN without double values - sql

I've got query
SELECT frst.Date,t1.Value
from
[ArchiveAnalog] frst
LEFT JOIN
(SELECT Date,Value FROM
[ArchiveAnalog] scnd
WHERE scnd.ID = 1) t1
ON t1.Date = frst.Date
order by frst.Date
but Join inserts values second time (not group with a main node)
if I do GROUP BY frst.Date , I've got error that I can't use t1 Value with it.
How can I make this JOIN without adding additional rows ?
Martin I want to show full Date and Value only if ID = 1 , also then I want to add t2 value column etc like here :
SELECT frst.Date,t1.Value,t2.Value
from
[ArchiveAnalog] frst
LEFT JOIN
(SELECT Date,Value FROM
[ArchiveAnalog] scnd
WHERE scnd.ID = 1) t1
ON t1.Date = frst.Date
LEFT JOIN
(SELECT Date,Value FROM
[ArchiveAnalog] scnd
WHERE scnd.ID = 2) t2
ON frst.Date = t2.Date
here I have x2 additional rows :S with doubling values, so I need to group them all with a some way.

You either need DISTINCT in the main query (if there's up to one row in t1 that you need), or GROUP BY. If you use GROUP BY, you need to aggregate t1.Value (e.g. sum, concatenate etc.).

Does this do what you need?
SELECT Date ,
MAX(CASE WHEN ID=1 THEN Value END) AS val1,
MAX(CASE WHEN ID=2 THEN Value END) AS val2
FROM [ArchiveAnalog]
WHERE ID IN (1,2) /*<-- Not sure if you need this line without seeing your data*/
GROUP BY Date

Related

Join Tables Where Absolute of Occurrences Equal to Absolute of Single Occurrence

Problem: I am currently trying to join two tables in Access where the absolute value of the total of multiple occurrences of one field in one table is equal to the absolute value of the occurrence in another table.
Am I able to use the Abs function in the WHERE statement? Everything I saw involved the function being used in the SELECT statement. Do I need to create separate queries to get the absolute values? It would also work if I were to check to see if they balance out rather than getting the absolute value.
In one table, a certain value will repeat multiple times while it will only appear once in the other table. How can I get the absolute values of the totals in order to compare it to the single occurrence in the other table? Thanks!
Table 1
Reference
Amount
55555
$15
55555
$20
Table 2
Reference
Amount
55555
-$35
If these are equal or if they balance out, they should appear on a query. If these aren't equal but the reference number and a partial amount appears, they should appear on another query.
The matching query is relatively simple. Just aggregate and compare the values:
select t2.reference, t2.amount
from (select reference, sum(amount) as amount
from table2
group by reference
) as t2 inner join
(select reference, sum(amount) as amount
from table1
group by reference
) as t1
on t1.reference = t2.reference
where t2.amount + t1.amount = 0;
However, the non-matches are much trickier -- because presumably a reference could be missing from either table. And MS Access does not support full join. One method is:
select t2.reference, t2.amount, t1.amount
from (select reference, sum(amount) as amount
from table2
group by reference
) as t2 left join
(select reference, sum(amount) as amount
from table1
group by reference
) as t1
on t1.reference = t2.reference
where t2.amount + t1.amount <> 0 or t1.amount is null
union all
select t1.reference, null, sum(amount)
from table1 as t1
where not exists (select 1 from table2 as t2 where t2.reference = t1.reference)
group by t1.reference;
Aggregate data in Table1 and join to Table2.
Consider:
SELECT Table2.*, SumAmt FROM Table2
INNER JOIN (SELECT Reference, Sum(Amount) AS SumAmt FROM Table1 GROUP BY Reference) AS T
ON Table2.Reference = T.Reference
WHERE SumAmt = -Table2.Amount;
You can list if the amounts match or not, no Abs is needed:
Select
Table2.Reference,
Table2.Amount,
(T.Total = -Table2.Amount) As T1Match
From
Table2
Inner Join
(Select
Table1.Reference,
Sum(Table1.Amount) As Total
From
Table1
Group By
Table1.Reference) As T
On T.Reference On Table2.Reference
you can use sub-query as follows:
select t1.reference from
(select reference, sum(amount) as amount from table1 group by reference) t1
join table2 t2
on abs(t1.amount) = abs(t2.amount)

Postgresql - Group By

I have a simple groupby scenario. Below is the output of the query.
Query is:
select target_date, type, count(*) from table_name group by target_date, type
The query and output is perfectly good.
My problem is I am using this in Grafana for plotting. That is Grafana with postgres as backend.
What happens is since "type2" category is missed on 01-10-2020 and 03-10-2020, type2 category never gets plotted (side to side bar plot) at all. Though "type2" is present in other days.
It is expecting some thing like
So whenever a category is missed in a date, we need a count with 0 value.
Need to handle this in query, as the source data cannot be modified.
Any help here is appreciated.
You need to create a list of all the target_date/type combinations. That can be done with a CROSS JOIN of two DISTINCT selects of target_date and type. This list can beLEFT JOINed to table_name to get counts for each combination:
SELECT dates.target_date, types.type, COUNT(t.target_date)
FROM (
SELECT DISTINCT target_date
FROM table_name
) dates
CROSS JOIN (
SELECT DISTINCT type
FROM table_name
) types
LEFT JOIN table_name t ON t.target_date = dates.target_date AND t.type = types.type
GROUP BY dates.target_date, types.type
ORDER BY dates.target_date, types.type
Demo on dbfiddle
You may use a calendar table approach here:
SELECT
t1.target_date,
t2.type,
COUNT(t3.target_date) AS count
FROM (SELECT DISTINCT target_date FROM yourTable) t1
CROSS JOIN (SELECT DISTINCT type FROM yourTable) t2
LEFT JOIN yourTable t3
ON t3.target_date = t1.target_date AND
t3.type = t2.type
GROUP BY
t1.target_date,
t2.type
ORDER BY
t1.target_date,
t2.type;
The idea here is to cross join subqueries finding all distinct target dates and types, to generate a starting point for the query. Then, we left join this intermediate table to your actual table, and find the counts for each date and type.
select t.target_date, tmp.type, sum(case when t.type = tmp.type then 1 else 0 end)
from your_table t
cross join (select distinct type from your_table) tmp
group by t.target_date, tmp.type
Demo

SQL carry forward non-null value within groups

The following thread (SQL QUERY replace NULL value in a row with a value from the previous known value) was very helpful to carry forward non-null values, but I'm can't figure out how to add a grouping column.
For example, I would like to do the following:
Example Data
Here is how I would have liked to code it:
UPDATE t1
SET
#n = COALESCE(number, #n),
number = COALESCE(number, #n)
GROUP BY grp
I know this isn't possible, and have seen several solutions that rely on inner joins, but those examples focus on aggregation rather than carrying forward values. For example: SQL Server Update Group by.
My attempt to make this work is to do something like the following:
UPDATE t1
SET
#n = COALESCE(number, #n),
number = COALESCE(number, #n)
FROM t1
INNER JOIN (
-- Lost on what to put in the inner join...
SELECT grp, COUNT(*) FROM t1 GROUP BY grp
) t2
on t1.grp = t2.grp
I think you can do what you want with a correlated subquery:
UPDATE t1
SET number = (SELECT TOP (1) tt1.number
FROM t tt1
WHERE tt1.grp = t1.grp AND tt1.? <= t1.? AND tt1.number IS NOT NULL
ORDER BY t1.? DESC
)
FROM t1
WHERE t1.number IS NULL;
The ? is for the column that specifies "forward" in your expression "carry forward".

Querying two tables to filter data using select case

I have two tables
Table 1 looks like this
ID Repeats
-----------
A 1
A 1
A 0
B 2
B 2
C 2
D 1
Table 2 looks like this
ID values
-----------
A 100
B 200
C 100
D 300
Using a view I need a result like this
ID values Repeats
-------------------
A 100 NA
B 200 2
C 100 2
D 300 1
that means, I want unique ID, its values and Repeats. Repeats value should display NA when there are multiple values against single ID and it should display the Repeats value in case there is single value for repeats.
Initially I needed to display the max value of repeats so I tried the following view
ALTER VIEW [dbo].[BookingView1]
AS
SELECT bv.*, bd2.Repeats FROM Table1 bv
JOIN
(
SELECT distinct bd.id, bd.Repeats FROM table2 bd
JOIN
(
SELECT Id, MAX(Repeats) AS MaxRepeatCount
FROM table2
GROUP BY Id
) bd1
ON bd.Id = bd1.Id
AND bd.Repeats = bd1.MaxRepeatCount
) bd2
ON bv.Id = bd2.Id;
and this returns the correct result but when trying to implement the CASE it fails to return unique ID results. Please help!!
One method uses outer apply:
select t2.*, t1.repeats
from table2 t2 outer apply
(select (case when max(repeats) = min(repeats) then max(repeats)
else 'NA'
end) as repeats
from table1 t1
where t1.id = t2.id
) t1;
Two notes:
This assumes that repeats is a string. If it is a number, you need to cast it to a string.
repeats is not null.
For the sake of completeness, I'm including another approach that will work if repeats is NULL. However, Gordon's answer has a much simpler query plan and should be preferred.
Option 1 (Works with NULLs):
SELECT
t1.ID, t2.[Values],
CASE
WHEN COUNT(*) > 1 THEN 'NA'
ELSE CAST(MAX(Repeats) AS VARCHAR(2))
END Repeats
FROM (
SELECT DISTINCT t1.ID, t1.Repeats
FROM #table1 t1
) t1
LEFT OUTER JOIN #table2 t2
ON t1.ID = t2.ID
GROUP BY t1.ID, t2.[Values]
Option 2 (does not contain explicit subqueries, but does not work with NULLs):
SELECT DISTINCT
t1.ID,
t2.[Values],
CASE
WHEN COUNT(t1.Repeats) OVER (PARTITION BY COUNT(DISTINCT t1.Repeats), t1.ID) > 1 THEN 'NA'
ELSE CAST(t1.Repeats AS VARCHAR(2))
END Repeats
FROM #table1 t1
LEFT OUTER JOIN #table2 t2
ON t1.ID = t2.ID
GROUP BY t1.ID, t2.[Values], t1.Repeats
NOTE:
This may not give desired results if table2 has different values for the same ID.

How do I compare 2 rows from the same table (SQL Server)?

I need to create a background job that processes a table looking for rows matching on a particular id with different statuses. It will store the row data in a string to compare the data against a row with a matching id.
I know the syntax to get the row data, but I have never tried comparing 2 rows from the same table before. How is it done? Would I need to use variables to store the data from each? Or some other way?
(Using SQL Server 2008)
You can join a table to itself as many times as you require, it is called a self join.
An alias is assigned to each instance of the table (as in the example below) to differentiate one from another.
SELECT a.SelfJoinTableID
FROM dbo.SelfJoinTable a
INNER JOIN dbo.SelfJoinTable b
ON a.SelfJoinTableID = b.SelfJoinTableID
INNER JOIN dbo.SelfJoinTable c
ON a.SelfJoinTableID = c.SelfJoinTableID
WHERE a.Status = 'Status to filter a'
AND b.Status = 'Status to filter b'
AND c.Status = 'Status to filter c'
OK, after 2 years it's finally time to correct the syntax:
SELECT t1.value, t2.value
FROM MyTable t1
JOIN MyTable t2
ON t1.id = t2.id
WHERE t1.id = #id
AND t1.status = #status1
AND t2.status = #status2
Some people find the following alternative syntax easier to see what is going on:
select t1.value,t2.value
from MyTable t1
inner join MyTable t2 on
t1.id = t2.id
where t1.id = #id
SELECT COUNT(*) FROM (SELECT * FROM tbl WHERE id=1 UNION SELECT * FROM tbl WHERE id=2) a
If you got two rows, they different, if one - the same.
SELECT * FROM A AS b INNER JOIN A AS c ON b.a = c.a
WHERE b.a = 'some column value'
I had a situation where I needed to compare each row of a table with the next row to it, (next here is relative to my problem specification) in the example next row is specified using the order by clause inside the row_number() function.
so I wrote this:
DECLARE #T TABLE (col1 nvarchar(50));
insert into #T VALUES ('A'),('B'),('C'),('D'),('E')
select I1.col1 Instance_One_Col, I2.col1 Instance_Two_Col from (
select col1,row_number() over (order by col1) as row_num
FROM #T
) AS I1
left join (
select col1,row_number() over (order by col1) as row_num
FROM #T
) AS I2 on I1.row_num = I2.row_num - 1
after that I can compare each row to the next one as I need