how to add two columns as result in single query - sql

I have below queries
select a.emp_id,a.AUTH_TYPE,b.NTE_TX as des1
from table a inner join NOTES b on b.TBL_ROW_ID=a.emp_id
where a.emp_id=56 and REF_NTE_TYP_ID=27
Output 1
select a.emp_id,a.AUTH_TYPE,b.NTE_TX as des2
from table a inner join NOTES b on b.TBL_ROW_ID=a.emp_id
where a.emp_id=56 and REF_NTE_TYP_ID=28
Output 2
Expected Output:
please help any one.

Simple Aggregation(MAX) will help you to get your expected output.
Try this:
select a.emp_id,a.AUTH_TYPE
,MAX(CASE WHEN REF_NTE_TYP_ID=27 THEN b.NTE_TX END) as des1
,MAX(CASE WHEN REF_NTE_TYP_ID=28 THEN b.NTE_TX END) as des2
from table a inner join NOTES b on b.TBL_ROW_ID=a.emp_id
where a.emp_id=56 and REF_NTE_TYP_ID IN(27,28)
GROUP BY a.emp_id,a.AUTH_TYPE

With Q1 As (
select 56 emp_id, 'diple' auth_type
),
Q2 As (
Select 'text2' Des2,27 ref_nte_type_id, 56 row_id
Union All
Select 'text1' Des2,28 ref_nte_type_id, 56 row_id
)
Select Q1.*,Q2.Des2,Q3.Des2 Des1
From Q1
Inner Join Q2
On Q1.Emp_Id=Q2.Row_Id
And Q2.Ref_Nte_Type_Id=27
Inner Join Q2 Q3
On Q1.Emp_Id=Q3.Row_Id
And Q3.Ref_Nte_Type_Id=28

If TBL_ROW_ID, REF_NTE_TYP_ID is unique in your table NOTESyou can also use subqueries:
select a.emp_id,a.AUTH_TYPE
, (SELECT b.NTE_TX
FROM NOTES b
WHERE b.TBL_ROW_ID=a.emp_id
AND REF_NTE_TYP_ID=27) as des1
, (SELECT b.NTE_TX
FROM NOTES b
WHERE b.TBL_ROW_ID=a.emp_id
AND REF_NTE_TYP_ID=28) as des2
from table a
where a.emp_id=56
If you have multiple text-entries you might want to concatenate these entries to just print one long text (replace the 2 occurences of SELECT b.NTE_TX with the following):
SELECT RTRIM(XMLAGG(XMLELEMENT(b.NTE_TX, CHR(10)).EXTRACT('//text()') ORDER BY b.NTE_TX).GetClobVal(),CHR(10))
I used CHR(10) as text delimiter, just replace it with any other string you want. And you might also want some other ORDER BYcondition.

Related

Can alias column used in a view for calculation in some other column?

CREATE VIEW dbo.myview1 As
SELECT
a.Id ,
a.Name ,
a.Age ,
CASE
WHEN b.PmtSched ='Monthly' THEN 12
WHEN b.PmtSched ='Quarterly' THEN 4
WHEN b.PmtSched ='Semi-Annual' THEN 2
WHEN b.PmtSched ='Annually' THEN 1
ELSE 12
END AS ABC,
SUM(a.Amount) *50 as TotalAmount ,
(a.AmtSpent - TotalAmount) * ABC as TOTALSPENDS
FROM dbo.User a join dbo.Details b on a.Id = b.Id
Here ABC and TotalAmount are Alias columns which needs to be used in computation in view and i am not able to use them.how to achieve this ?is there any way we could do this or we cant ?please help.
The simple solution to your problem is to repeat the expression, use a subquery, or use a CTE.
However, the more intelligent method is to add a reference table for payment schedules. This would look like:
create table PaymentSchedules (
PaymentScheduleId int identity(1, 1) primary key,
ScheduleName varchar(255),
FrequencyPerYear float -- this could be less often than once per year
);
Then the view would look like:
CREATE VIEW dbo.myview1 As
SELECT a.Id, a.Name, a.Age, ps.FrequencyPerYear,
SUM(a.Amount) * 50 as TotalAmount,
(a.AmtSpent - SUM(a.Amount) * 50) * ps.FrequencyPerYear as TOTALSPENDS
FROM dbo.User a join
dbo.Details b
on a.Id = b.Id join
dbo.PaymentSchedules ps
on ps.PaymentScheduleId = a.PamentScheduleId;
Yes, you can use it and you don't need neither subqueries, nor CTEs. It's a simple CROSS APPLY. It's quite elegant and doesn't hurt readability. If you need more information, read here.
Please see this example:
CREATE VIEW dbo.myview1
AS
SELECT A.Id
, A.Name
, A.Age
, SUM(A.Amount) * 50 AS TotalAmount
, (A.AmtSpent - TotalAmount) * T.ABC AS TotalSpends
FROM dbo.[User] AS A
CROSS APPLY (
SELECT CASE B.PmtSched
WHEN 'Monthly' THEN 12
WHEN 'Quarterly' THEN 4
WHEN 'Semi-Annual' THEN 2
WHEN 'Annually' THEN 1
ELSE 12
END) AS T(ABC)
INNER JOIN dbo.Details AS B
ON A.Id = B.Id;
Simple answer "NO"
It's impossible to do this without a subquery.
or
You need to use CTE
Below query will help you to get what you need.
;WITH Amount
(
SELECT a.Id,a.NAME,a.Age,a.AmtSpent,
CASE WHEN b.PmtSched ='Monthly' THEN 12
WHEN b.PmtSched ='Quarterly' THEN 4
WHEN b.PmtSched ='Semi-Annual' THEN 2
WHEN b.PmtSched ='Annually' THEN 1
ELSE 12
END AS ABC
,SUM(a.Amount) * 50 AS TotalAmount
FROM
dbo.[User] a
INNER JOIN
dbo.Details b ON a.Id = b.Id
GROUP BY id, NAME, age, abc, a.AmtSpent, TotalAmount
)
Now you can call those alias for calculation.
SELECT id,NAME,age,abc,(a.AmtSpent - TotalAmount) * ABC AS TOTALSPENDS FROM Amount

Get Incremental index for specific rows

I want to get the incremental index when note exists for the row. I am trying to achieve the same with ROW_Number() but it seems there is a problem with the method being used to generate it.
SELECT * RowNo,
(SELECT CASE
WHEN LEN(Value) > 0 THEN ROW_NUMBER()
OVER (
ORDER BY ID)
ELSE ''
END
FROM Dictionary
WHERE ID = ABC.ID) Note
FROM ABCD AS ABC WITH(NOLOCK)
INNER JOIN XYZ AS XYZ WITH(NOLOCK)
ON ABC.Id = XYZ.ID
WHERE ABC.Id = 10
output expected:
ID Name Note
1 A 1
2 B
3 C 2
4 D
5 E
6 F 3
The subquery isn't needed here, and you want to use the partition by argument to separate values having len(value)>0 from those having no value:
SELECT
ID,
Name,
CASE WHEN LEN(Value)>0 THEN ROW_NUMBER() OVER (
PARTITION BY CASE WHEN LEN(Value)>0 THEN 1 ELSE 0 END
ORDER BY ID) ELSE '' END as Note
FROM ABCD AS ABC WITH(NOLOCK)
INNER JOIN XYZ AS XYZ WITH(NOLOCK)
ON ABC.Id = XYZ.ID
Where ABC.Id = 10
I think maybe you need to change the approach to make the Dictionary query the "main" query. It's hard to say without knowing exactly what your tables look like. Which Table does the "Id" in your expected output come from?
Try like this:
WITH cte AS (
SELECT ID, ROW_NUMBER() OVER (ORDER BY ID) AS Note
FROM Dictionary WHERE ID=10
AND LEN(Value)>0
)
SELECT ABC.ID, [Name], cte.Note
FROM ABCD AS ABC WITH(NOLOCK)
INNER JOIN XYZ AS XYZ WITH(NOLOCK) ON ABC.Id = XYZ.ID
LEFT OUTER JOIN cte ON ABC.Id=cte.ID

Showing specific output data based on duplicate rows and null values [postgresql]

I'm using the following SQL (with a union to two similar queries):
SELECT
distinct a.source,
a.p_id,
a.name,
b.prod_count,
b.prod_amt,
'Def' as prod_type
FROM
dwh.attribution_product_count a
LEFT OUTER JOIN
(
SELECT
distinct source,
p_id,
name,
sum(acct_count) as prod_count,
sum(acct_amt) as prod_amt
FROM
dwh.prod_count
WHERE
month = 3 AND
default_banner_flag = 0 AND
loan_flag = 3
GROUP BY
source,
name,
p_id ) as b
ON
a.p_id = b.p_id
UNION
SELECT
distinct a.source,
a.p_id,
a.name,
b.prod_count,
b.prod_amt,
'Other' as prod_type
FROM
dwh.attribution_product_count a
LEFT OUTER JOIN
(
SELECT
distinct source,
p_id,
name,
sum(acct_count) as prod_count,
sum(acct_amt) as prod_amt
FROM
dwh.prod_count
WHERE
month = 3 AND
default_banner_flag = 1 AND
loan_flag = 3
GROUP BY
source,
name,
p_id
ORDER BY
name ) as b
ON
a.p_id = b.p_id
The output I'm getting looks like this:
Essentially since FakeName #2 has one row showing actual numbers (not null), I ONLY want FakeName #2 to show up. This means I also want the null row for FakeName #2. But, since FakeName #1 and #3 have 2 null rows, I don't need them to show. What type of SQL command (or edit to my query) can accomplish this?
Firstly, if I read your query correctly, you can eliminate the need for a UNION by using CASE and IN. You also have a couple of bogus DISTINCTs in there (since you're using GROUP BY anyway). That gives:
SELECT DISTINCT
a.source,
a.p_id,
a.name,
b.prod_count,
b.prod_amt,
Case When default_banner_flag = 0 Then 'Def' Else 'Other' End as prod_type
FROM
dwh.attribution_product_count a
LEFT OUTER JOIN
(
SELECT
source,
p_id,
name,
default_banner_flag,
sum(acct_count) as prod_count,
sum(acct_amt) as prod_amt
FROM
dwh.prod_count
WHERE
month = 3 AND
default_banner_flag in (0, 1) AND
loan_flag = 3
GROUP BY
source,
name,
p_id,
default_banner_flag
) as b
ON
a.p_id = b.p_id
However, what you actually want is information about those p_ids which have at least one row in dwh.prod_count, so I think you can change your whole query around to use that as the sub-select:
SELECT
a.source,
a.p_id,
a.name,
sum(acct_count) as prod_count,
sum(acct_amt) as prod_amt,
Case When default_banner_flag = 0 Then 'Def' Else 'Other' End as prod_type
FROM
dwh.attribution_product_count a
LEFT OUTER JOIN
dwh.prod_count b
On a.p_id = b.p_id
INNER JOIN
(
SELECT DISTINCT
p_id
FROM
dwh.prod_count
WHERE
month = 3 AND
default_banner_flag in (0, 1) AND
loan_flag = 3
) as c
ON a.p_id = c.p_id
WHERE
month = 3 AND
default_banner_flag in (0, 1) AND
loan_flag = 3
(You could also rewrite this as a WHERE p_id IN ( sub-select ) or with a little fiddling WHERE EXISTS ( ... ), but this seemed the easiest version to demonstrate.)
Note that I haven't actually tested any of these queries, but I think they're logically sound.

Produce result table trom multiple tables

SQL Server 2008 R2
I have 3 tables contained data for 3 different types of events
Type1, Type2, Type3 with two columns:
DatePoint ValuePoint
I want to produce result table which would look like that:
DatePoint TotalType1 TotalType2 TotalType3
I've started from that
SELECT [DatePoint]
,SUM(ValuePoint) as TotalType1
FROM [dbo].[Type1]
GROUP BY [DatePoint]
ORDER BY [DatePoint]
SELECT [DatePoint]
,SUM(ValuePoint) as TotalType2
FROM [dbo].[Type2]
GROUP BY [DatePoint]
ORDER BY [DatePoint]
SELECT [DatePoint]
,SUM(ValuePoint) as TotalType3
FROM [dbo].[Type3]
GROUP BY [DatePoint]
ORDER BY [DatePoint]
So I have three result but I need to produce one (Date TotalType1 TotalType2 TotalType3), what I need to do next achieve my goal?
UPDATE
Forgot to mention that DatePoint which is exists in one type may or may not exist in another
Here's my take. I assume that you don't have the same datetime values in every table (certainly, the stuff I get to work with is never so consistant). There should be an easier way to do this, but once you're past two outer joins things can get pretty tricky.
SELECT
dp.DatePoint
,isnull(t1.TotalType1, 0) TotalType1
,isnull(t2.TotalType2, 0) TotalType2
,isnull(t3.TotalType3, 0) TotalType3
from (-- Without "ALL", UNION will filter out duplicates
select DatePoint
from Type1
union select DatePoint
from Type2
union select DatePoint
from Type3) dp
left outer join (select DatePoint, sum(ValuePoint) TotalType1
from Type1
group by DatePoint) t1
on t1.DatePoint = db.DatePoint
left outer join (select DatePoint, sum(ValuePoint) TotalType2
from Type2
group by DatePoint) t2
on t2.DatePoint = db.DatePoint
left outer join (select DatePoint, sum(ValuePoint) TotalType3
from Type3
group by DatePoint) t3
on t3.DatePoint = db.DatePoint
order by dp.DatePoint
Suppose some distinct could help, but the general idea should be the following:
SELECT
t.[DatePoint],
SUM(t1.ValuePoint) as TotalType1,
SUM(t2.ValuePoint) as TotalType2,
SUM(t3.ValuePoint) as TotalType3
FROM
(
SELECT [DatePoint] FROM [dbo].[Type1]
UNION
SELECT [DatePoint] FROM [dbo].[Type2]
UNION
SELECT [DatePoint] FROM [dbo].[Type3]
) as t
LEFT JOIN
[dbo].[Type1] t1
ON
t1.[DatePoint] = t.[DatePoint]
LEFT JOIN
[dbo].[Type2] t2
ON
t2.[DatePoint] = t.[DatePoint]
LEFT JOIN
[dbo].[Type3] t3
ON
t3.[DatePoint] = t.[DatePoint]
GROUP BY
t.[DatePoint]
ORDER BY
t.[DatePoint]
To avoid all of the JOINs:
SELECT
SQ.DatePoint,
SUM(CASE WHEN SQ.type = 1 THEN SQ.ValuePoint ELSE 0 END) AS TotalType1,
SUM(CASE WHEN SQ.type = 2 THEN SQ.ValuePoint ELSE 0 END) AS TotalType2,
SUM(CASE WHEN SQ.type = 3 THEN SQ.ValuePoint ELSE 0 END) AS TotalType3
FROM (
SELECT
1 AS type,
DatePoint,
ValuePoint
FROM
dbo.Type1
UNION ALL
SELECT
2 AS type,
DatePoint,
ValuePoint
FROM
dbo.Type2
UNION ALL
SELECT
3 AS type,
DatePoint,
ValuePoint
FROM
dbo.Type3
) AS SQ
GROUP BY
DatePoint
ORDER BY
DatePoint
From the little information provided though, it seems like there are some flaws in the database design, which is probably part of the reason that querying the data is so difficult.

Find records with exact matches on a many to many relationship

I have three tables that look like these:
PROD
Prod_ID|Desc
------------
P1|Foo1
P2|Foo2
P3|Foo3
P4|Foo4
...
RAM
Ram_ID|Desc
------------
R1|Bar1
R2|Bar2
R3|Bar3
R4|Bar4
...
PROD_RAM
Prod_ID|Ram_ID
------------
P1|R1
P2|R2
P3|R1
P3|R2
P3|R3
P4|R3
P5|R1
P5|R2
...
Between PROD and RAM there's a Many-To-Many relationship described by the PROD_RAM table.
Given a Ram_ID set like (R1,R3) I would like to find all the PROD that has exactly ONE or ALL of the RAM of the given set.
Given (R1,R3) should return for example P1,P4 and P5; P3 should not be returned because has R1 and R3 but also R2.
What's the fastest query to get all the PROD that has exactly ONE or ALL of the Ram_ID of a given RAM set?
EDIT:
The PROD_RAM table could contain relationship bigger than 1->3 so, "hardcoded" checks for count = 1 OR = 2 are not a viable solution.
Another solution you could try for speed would be like this
;WITH CANDIDATES AS (
SELECT pr1.Prod_ID
, pr2.Ram_ID
FROM PROD_RAM pr1
INNER JOIN PROD_RAM pr2 ON pr2.Prod_ID = pr1.Prod_ID
WHERE pr1.Ram_ID IN ('R1', 'R3')
)
SELECT *
FROM CANDIDATES
WHERE CANDIDATES.Prod_ID NOT IN (
SELECT Prod_ID
FROM CANDIDATES
WHERE Ram_ID NOT IN ('R1', 'R3')
)
or if you don't like repeating the set conditions
;WITH SUBSET (Ram_ID) AS (
SELECT 'R1'
UNION ALL SELECT 'R3'
)
, CANDIDATES AS (
SELECT pr1.Prod_ID
, pr2.Ram_ID
FROM PROD_RAM pr1
INNER JOIN PROD_RAM pr2 ON pr2.Prod_ID = pr1.Prod_ID
INNER JOIN SUBSET s ON s.Ram_ID = pr1.Ram_ID
)
, EXCLUDES AS (
SELECT Prod_ID
FROM CANDIDATES
LEFT OUTER JOIN SUBSET s ON s.Ram_ID = CANDIDATES.Ram_ID
WHERE s.Ram_ID IS NULL
)
SELECT *
FROM CANDIDATES
LEFT OUTER JOIN EXCLUDES ON EXCLUDES.Prod_ID = CANDIDATES.Prod_ID
WHERE EXCLUDES.Prod_ID IS NULL
One way to do this would be something like the following:
SELECT PROD.Prod_ID FROM PROD WHERE
(SELECT COUNT(*) FROM PROD_RAM WHERE PROD_RAM.Prod_ID = PROD.Prod_ID) > 0 AND
(SELECT COUNT(*) FROM PROD_RAM WHERE PROD_RAM.Prod_ID = PROD.Prod_ID AND PROD.Ram_ID <>
IFNULL((SELECT TOP 1 Ram_ID FROM PROD_RAM WHERE PROD_RAM.Prod_ID = PROD.Prod_ID),0)) = 0
SELECT Prod_ID
FROM
( SELECT Prod_ID
, COUNT(*) AS cntAll
, COUNT( CASE WHEN Ram_ID IN (1,3)
THEN 1
ELSE NULL
END
) AS cntGood
FROM PROD_RAM
GROUP BY Prod_ID
) AS grp
WHERE cntAll = cntGood
AND ( cntGood = 1
OR cntGood = 2 --- number of items in list (1,3)
)
Not at all sure if it's the fastest way. You'll have to try different ways to write this query (using JOINs and NOT EXISTS ) and test for speed.