Full join in two columns with repeated values - sql

I have two tables that look like this:
sMinMax:
PartNo baseID Min Max
11795 1 1 1
11795 5 0 0
11795 6 1 1
01655 65 2 3
vsStock:
PartNo baseID Qty
11795 1 1
11795 1 1
11795 55 1
I would like to join them so I get a table that shows all the columns together for all the parNo en bases like this:
result:
PartNo baseID Min Max Qty
11795 1 1 1 2
11795 5 0 0 null
11795 6 1 1 null
11795 55 null null 1
01655 65 2 3 null
So I would just do this with a full outer join on two columns but this gives the same results that I would expect from a left join. I tried 1000 things but this is my last try:
SELECT
a.sPart_ID
,a.uRALBase_ID
,a.MinQty
,a.MaxQty
,b.Qty
FROM [RALNHVTST].[dbo].[sMinMax] as a
FULL OUTER JOIN [RALNHVTST].[dbo].[vsStockList] as b
ON a.sPart_ID = b.sPart_ID
AND a.uRALBase_ID = b.uRALBase_ID
WHERE a.sPart_ID IS NOT NULL
AND a.sPart_ID = 1159
ORDER BY a.sPart_ID
but as I said this gives me the same results as a LEFT JOIN. Anyone have an idea what I'm doing wrong?

Something like that? This query gives me same result as you expected.
SELECT
CASE WHEN a.PartNo IS NOT NULL THEN a.PartNo ELSE b.PartNo END AS PartNo
,CASE WHEN a.baseId IS NOT NULL THEN a.baseId ELSE b.baseId END AS baseId
,a.[Min]
,a.[Max]
,SUM(b.Qty) AS Qty
FROM [dbo].[sMinMax] as a
FULL JOIN [dbo].[vsStock] as b
ON a.partNo = b.partNo
AND a.baseId = b.baseId
GROUP BY
CASE WHEN a.PartNo IS NOT NULL THEN a.PartNo ELSE b.PartNo END,
CASE WHEN a.baseId IS NOT NULL THEN a.baseId ELSE b.baseId END,
a.[Min],
a.[Max]
ORDER BY
CASE WHEN a.PartNo IS NOT NULL THEN a.PartNo ELSE b.PartNo END

Filtering in a full join is tricky. I would recommend filtering and aggregating in subqueries:
SELECT COALESCE(sm.sPart_ID, s.sPart_Id) as sPartId,
COALESCE(sm.uRALBase_ID, sm.uRALBase_ID
sm.MinQty, sm.MaxQty, s.Qty
FROM (SELECT sm.*
FROM [RALNHVTST].[dbo].[sMinMax] sm
WHERE sm.sPart_ID = 1159
) sm FULL OUTER JOIN
(SELECT s.sPart_ID, s.uRALBase_ID, SUM(qty) as qty
FROM [RALNHVTST].[dbo].[vsStockList] s
WHERE s.sPart_ID = 1159
GROUP BY s.sPart_ID, s.uRALBase_ID
) s
ON sm.sPart_ID = s.sPart_ID AND
sm.uRALBase_ID = s.uRALBase_ID
ORDER BY sPart_ID

Related

What will be the query for fetching all the records from left table and matching records from the right tables?

What will be the query for fetching all the records from left table and matching records from the right tables?
Tables:
properties:
id cid property_name
1 1 Property1
2 1 Property2
3 1 Property3
4 1 Property4
property_medias:
id cid property_id media_file_id
1 1 1 1
2 1 1 2
3 1 1 4
4 1 2 5
5 1 2 6
media_files
id cid media_alt
1 1 NULL
2 1 pqr
3 1 NULL
4 1 ttt
5 1 NULL
6 1 NULL
Expected Output:
id cid property_name media_alt
1 1 Property1 YES
2 1 Property2 NO
3 1 Property3 -
4 1 Property4 -
Explanation of output:
Property1 is having atleast one record having media_alt IS NOT NULL hence media_alt is 'YES'
Property2 is having all the records NULL for media_alt hence media_alt is 'NO'
Property3 and Property4 are not having any media associated with it hence media_alt is '-'.
I tried with this query but it is giving me duplicate records of properties.
SELECT distinct p.id, p.property_name, mf.media_alt
FROM
properties AS p
JOIN property_medias pm ON ( pm.property_id = p.id AND pm.cid = p.cid)
JOIN media_files mf ON ( mf.id = pm.media_file_id AND mf.cid = pm.cid )
WHERE
p.cid = 1
ORDER BY p.property_name
Please help me in the right direction.
You are describing a LEFT JOIN and GROUP BY:
SELECT p.id, p.property_name,
(CASE WHEN COUNT(mf.media_alt) > 0 THEN 'YES'
WHEN COUNT(mf.cid) > 0 THEN 'NO'
ELSE '-'
END) as media_alt
FROM properties p LEFT JOIN
property_medias pm
ON pm.property_id = p.id AND pm.cid = p.cid LEFT JOIN
media_files mf
ON mf.id = pm.media_file_id AND mf.cid = pm.cid
WHERE p.cid = 1
GROUP BY p.id, p.property_name;
The first COUNT() is determining if any of the column values are not NULL. The second is determining if there are any matches.
You could also phrase this using EXISTS:
SELECT p.id, p.property_name,
(CASE WHEN EXISTS (SELECT 1
FROM property_medias pm LEFT JOIN
media_files mf
ON mf.id = pm.media_file_id AND mf.cid = pm.cid
WHERE pm.property_id = p.id AND
pm.cid = p.cid AND
mf.media_alt IS NOT NULL
)
THEN 'YES'
WHEN EXISTS (SELECT 1
FROM property_medias pm
WHERE pm.property_id = p.id AND
pm.cid = p.cid
)
THEN 'NO'
ELSE '-'
END) as media_alt
FROM properties p
WHERE p.cid = 1;
This saves the outer aggregation, but may not have any performance advantage in Postgres.

Query to get translation for each languages

Please help me to create query. I have table with languages like
Id Code
---------
1 EN
2 DE
3 RU
and table with translations
Id Code LanguageId Value
------------------------------------------
1 1 1 EnglishTranslation
2 1 3 RussianTranslation
3 2 1 EnglishTranslation
4 2 2 DeutschTranslation
5 3 1 EnglishTranslation
I'm trying to get this result
Id Code LanguageId Value
------------------------------------------
1 1 1 EnglishTranslation
1 1 2 NULL
2 1 3 RussianTranslation
3 2 1 EnglishTranslation
4 2 2 DeutschTranslation
4 2 3 NULL
5 3 1 EnglishTranslation
5 3 2 NULL
5 3 3 NULL
Need to get translations for all languages by Code from Translations table So far I try
select
T.id, T.Code, L.Id, T.Value
from Languages L
left join Translations T on T.LanguageId = L.Id
but I got not expected result. Could you please suggest
http://sqlfiddle.com/#!6/e9bed/1
You can use CROSS JOIN operator to construct a cartesian product of (LanguageId, Code) pairs, and left-join translation table to it:
SELECT
t.Id, y.Code, x.LanguageId, t.Value
FROM
((SELECT Id AS LanguageId FROM Languages) AS x
CROSS JOIN
(SELECT DISTINCT(Code) AS Code FROM Translations) AS y)
LEFT OUTER JOIN Translations t ON y.Code=t.Code AND x.LanguageId=t.LanguageId
ORDER BY t.Code, t.LanguageId
Note that this wouldn't produce a valid translation Id for rows missing from Translations, i.e. the result would look like this:
Id Code LanguageId Value
---------------------------------------------
1 1 1 EnglishTranslation
NULL 1 2 NULL
2 1 3 RussianTranslation
3 2 1 EnglishTranslation
4 2 2 DeutschTranslation
NULL 2 3 NULL
5 3 1 EnglishTranslation
NULL 3 2 NULL
NULL 3 3 NULL
Demo.
I resolved the issue and got the result that you expected.
Run the below query:
SELECT
(CASE
WHEN T.Id is null and lc.Code = 1 THEN 1
WHEN T.Id is null and lc.Code = 2 THEN 4
WHEN T.Id is null and lc.Code = 3 THEN 5
ELSE T.Id
END) as Id,
lc.Code, lc.Id as LanguageId, T.Value from
(SELECT x.Id, y.Code from (SELECT Id FROM Languages) x cross join (SELECT DISTINCT(Code) as Code FROM Translations) y) as lc
left outer join Translations T ON lc.Id = T.LanguageId and lc.Code = T.Code
order by Id, Code, LanguageId
You can also see the solution in the below link:
http://sqlfiddle.com/#!6/e9bed/30
Hopefully it will work as you like.

How to count if all documents in a group have a value set to 1?

In a document review tool, one can create "batches" of documents. A batch is a group of related documents, identified by GroupID.
These groups of documents are presented to reviewers, who update a field called Testcompleted. This field has 3 possible states: 1, 0 or null. The number of documents in a group varies.
In the example below I have 3 groups ("batches") of documents. The first batch (batch_0001), for instance, has 2 documents (58 and 59).
#Document
ArtifactID Testcompleted GroupID
--------------------------------------
58 1 4
59 1 4
60 null 6
61 1 6
62 null 7
63 null 7
64 null 7
#DocumentBatch
BatchArtifactID DocumentArtifactID
-------------------------------------
66 58
66 59
67 60
67 61
68 62
68 63
68 64
#Batch
ArtifactID Name
------------------------
66 batch_0001
67 batch_0002
68 batch_0003
I need to know when a batch is completed -- that is: when all documents in that batch have the Testcompleted field set to 1. In the example, this is the case for batch_0001.
The output I am looking for is:
batch documents reviewed completed
------------------------------------------------------
batch_0001 2 2 yes
batch_0002 2 1 no
batch_0003 3 0 no
I started by joining the tables:
select
*
from
#Document d
left join #DocumentBatch db
on db.DocumentArtifactID = b.ArtifactID
left join #Batch b
on db.BatchArtifactID = b.ArtifactID
where
d.Testcompleted = 1
;
This obviously does not return the result I need, but I am stuck. Some help on how to solve this would be greatly appreciated.
select
b.name,
count(db.DocumentArtifactID) as documents,
-- count only completed
count(case when d.Testcompleted = 1 then d.ArtifactID end) as reviewed,
-- if the minimum = 1 there's no 0 or NULL
case when min(cast(Testcompleted as tinyint)) = 1 then 'yes' else 'no' end as completed
from
#Batch b
left join #DocumentBatch db
on db.BatchArtifactID = b.ArtifactID
left join #Document d
on db.DocumentArtifactID = d.ArtifactID
group by b.name;
If there are no missing rows you can switch to Inner Joins...
What you want is aggregation,so you need a group by. Something like this:
select b.name as batchname, count(d.ARtifactID) as numdocuments,
sum(case when d.testCompleted = 1 then 1 else 0 end) as NumCompleted,
(case when sum(case when d.testCompleted = 1 then 0 else 1 end) > 0
then 'No'
else 'Yes'
end) as AllCompleted
from #Batch b left join
#DocumentBatch db
on db.BatchArtifactID = b.ArtifactID
#Document d left join
on db.DocumentArtifactID = b.ArtifactID left join
group by b.name;
I don't think outer joins are needed. You should be able to use inner join, unless there are batches with no documents. If you do use outer joins, starting with #Batch makes more sense than #Document, because you are aggregating at the batch level.
You can try something like this:
select b.name
, count(*) as documents
, sum(d.Testcompleted) as reviewed
, (case when count(*) = sum(d.Testcompleted) then 'yes' else 'no' end) as completed
from [#Document] d
join [#DocumentBatch] db on db.DocumentArtifactID = d.ArtifactID
join [#Batch] b on db.BatchArtifactID = b.ArtifactID
group by b.name
SQLFiddle
count(*) includes into calculation all values;
sum(d.Testcompleted) count only cases where Testcompleted is 1;

Show null and not num values

My query
with with_user_earns as (
-- get father information (start)
select father.id, father.str_name, father.id_father, father.ind_father_side_type, 1 as int_user_level from tb_user father where id = #v_user_id
union all
-- get son information (stop condition)
select son.id, son.str_name, son.id_father, son.ind_father_side_type, WUE.int_user_level + 1
from tb_user as son inner join with_user_earns as WUE on son.id_father = WUE.id
where son.id_father is not null and WUE.int_user_level < #v_max_level
)
select aux.*
from (
-- show result
select with_user_earns.id id_son, with_user_earns.str_name str_son_name, with_user_earns.id_father, father.str_name str_father_name, with_user_earns.ind_father_side_type, with_user_earns.int_user_level, isnull(sum(o.int_score), 0) as int_score
from with_user_earns inner join tb_order o on o.id_user = with_user_earns.id
inner join tb_user as father on father.id = with_user_earns.id_father
where o.dt_insert between #v_cycle_begin and #v_cycle_end and o.ind_payment_status = 3
group by with_user_earns.id, with_user_earns.str_name, with_user_earns.id_father, with_user_earns.ind_father_side_type, with_user_earns.int_user_level, father.str_name
) as aux
order by aux.int_user_level, aux.id_son
The table with_user_earns contains a lot of users (mult nivel hierarchy).
Then I want to join with tb_order to get int_score 0 if the user sell nothing and if the user sell anything I want the sum of it.
I tried put left join, full outer join, ... But no one works perfect
What a need to do?
My result:
id_son int_score
1 100
2 11100
3 100
10 300
Expected result:
id_son int_score
1 100
2 11100
3 100
4 0
5 0
6 0
7 0
8 0
9 0
10 300

query result not return value in row

i have two tables join to show the count value of first table and i write a query like this
i have a table that contain category called [PEBPC] that contain a 3 producer category
USE [P1OTP]
SELECT pe.[ID] AS [No]
,pe.[NAME] AS [ProducerType]
,coalesce(COUNT(CASE tp.[NewProducer] WHEN 0 THEN 1 ELSE NULL END),0) AS [NewProducers]
,coalesce(COUNT(CASE tp.[NewProducer] WHEN 1 THEN 1 ELSE NULL END),0) AS [ExistProducer]
,coalesce(COUNT(tp.[NewProducer]),0) AS [Total]
FROM [TPDCS]
LEFT JOIN [PEBPC] pe ON pe.[ID] = tp.[estbProducerID]
WHERE 1 = 1
AND tp.[OrganizationAddrProvince] IS NOT NULL
AND tp.[OrganizationAddrProvince] = '81'
AND tp.[libDocumentID] IN(SELECT [ParentID] FROM [TPDTS] WHERE [CategoryID] IS NOT NULL) >
GROUP BY pe.[ID]
,pe.[NAME] ORDER BY pe.[ID]
when this query run it's only show just 2 category because this province have just 1 and 2 category
No Type of Producer NewProducer ExistProducer Total
1 Citizen Producer 102 0 102
2 sole proprietorship 45 0 45
i tried coalesce, count or something that can return 0 but it's doesn't work
i need them to return like this
No Type of Producer NewProducer ExistProducer Total
1 Citizen Producer 102 0 102
2 sole proprietorship 45 0 45
3 SME Producer 0 0 0
How about this? Use PEBPC as your main table and left join it to TPDCS. Note that I move all your WHERE conditions in the JOIN part:
SELECT
pe.[ID] AS [No]
,pe.[NAME] AS [ProducerType]
,COALESCE(COUNT(CASE tp.[NewProducer] WHEN 0 THEN 1 ELSE NULL END),0) AS [NewProducers]
,COALESCE(COUNT(CASE tp.[NewProducer] WHEN 1 THEN 1 ELSE NULL END),0) AS [ExistProducer]
,COALESCE(COUNT(tp.[NewProducer]),0) AS [Total]
FROM [PEBPC] pe
LEFT JOIN [TPDCS] tp ON pe.[ID] = tp.[estbProducerID]
AND tp.[OrganizationAddrProvince] IS NOT NULL
AND tp.[OrganizationAddrProvince] = '81'
AND tp.[libDocumentID] IN(SELECT [ParentID] FROM [TPDTS] WHERE [CategoryID] IS NOT NULL)
GROUP BY pe.[ID], pe.[NAME]
ORDER BY pe.[ID]