TSQL JOIN Clarification - sql-server

Suppose i have two tables
declare #emp table
(
EmpID int,
EmpName varchar(10)
)
declare #Remu table
(
EmpID int,
Sal Decimal(10,2),
PaidYear varchar(10)
)
I want maximum salary grouped on PaidYear (With Ties)
Expected OUTPUT
EmpID EmpName PaidYear Sal
1 Jon 2001 2000
2 Smith 2001 2000
3 Nash 2003 4000
4 Hoge 2005 5000
5 Peter 2005 5000
I have an issue when using Join
select e.EmpID,e.EmpName,r.Sal,r.PaidYear from #emp e
inner join
(select max(Sal) as Sal,PaidYear from #Remu group by PaidYear)r
on e.EmpID=???
when i select EmpID in
select max(Sal) as Sal,PaidYear from #Remu group by PaidYear
i have to Group by PaidYear and EmpID,which won't give the desired result as i expected.
How to solve this.I want a query which should be compatible with SQL Server 2000.

select e.EmpID,e.EmpName,r.Sal,r.PaidYear
from #emp e inner join #Remu r on e.EmpId = r.EmpId
where r.sal in (select max(sal) from #remu group by paidyear)

Each year needs to determine a single max salary specific to that year.
select e.EmpID
, e.EmpName
, r.Sal
, r.PaidYear
from #emp as e
inner join #Remu as r
on e.EmpId = r.EmpId
where r.sal = (select max(sal)
from #remu
where paidyear = r.PaidYear ' makes it year specific
)
Data To Test:
declare #emp table
(
EmpID int,
EmpName varchar(10)
)
declare #Remu table
(
EmpID int,
Sal Decimal(10,2),
PaidYear varchar(10)
)
insert into #emp (EmpID, EmpName)
values(1, 'Jon')
insert into #emp (EmpID, EmpName)
values(2, 'Smith')
insert into #emp (EmpID, EmpName)
values(3, 'Nash')
insert into #emp (EmpID, EmpName)
values(4, 'Hoge')
insert into #emp (EmpID, EmpName)
values(5, 'Peter')
Insert into #Remu (EmpID, Sal, PaidYear)
values(1, 2000, '2001')
Insert into #Remu (EmpID, Sal, PaidYear)
values(2, 4999, '2001')
Insert into #Remu (EmpID, Sal, PaidYear)
values(2, 8000, '2003')
Insert into #Remu (EmpID, Sal, PaidYear)
values(3,4000, '2003')
Insert into #Remu (EmpID, Sal, PaidYear)
values(4, 5000, '2005')
Insert into #Remu (EmpID, Sal, PaidYear)
values(5, 4999, '2005')
Results:
EmpID EmpName Sal PaidYear
4 Hoge 5000.00 2005
2 Smith 8000.00 2003
2 Smith 4999.00 2001

Related

SQL Server: max of date

Table 1
RefId Name
----- ----
1 A
2 B
Table 2
RefId Date
----- -----
1 29/03/2018 07:15
1 29/03/2018 07:30
2 29/03/2018 07:35
2 29/03/2018 07:40
I would like the result to be as follows (Refid name and the max(date) from table 1 and 2 for that refid)
1 A 29/03/2018 07:30
2 B 29/03/2018 07:40
Query used
select
table1.refId, table1.name,
(select max(date) from table2)
from
table1, table2
where
table1.refid = table2.refid
group by
table2.refid
I am getting the following error message
Column is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
Use JOIN and the aggregate function MAX with GROUP BY to select the max date for each RefId.
Query
select [t1].[RefId], [t1].[Name], max([t2].[date] as [date]
from [Table1] [t1]
join [Table2] [t2]
on [t1].[RefId] = [t2].[RefId]
group by [t1].[RefId], [t1].[Name];
'29/03/2018 07:15' is nvarchar-type, you need datetime.
nvarchar convert to datetime: SELECT CONVERT(datetime, '29/03/2018 07:15', 103)
Answer to your example:
DECLARE #Table1 TABLE(RefId int, Name nvarchar(10));
INSERT INTO #Table1(RefId, Name) VALUES(1, 'A'), (2, 'B');
DECLARE #Table2 TABLE(RefId int, [Date] nvarchar(50));
INSERT INTO #Table2(RefId, [Date])
VALUES
(1, '29/03/2018 07:15'),
(1, '29/03/2018 07:30'),
(2, '29/03/2018 07:35'),
(2, '29/03/2018 07:40');
SELECT t1.RefId, t1.Name, t2.Date
FROM #Table1 AS t1
INNER JOIN
(SELECT RefId, MAX(CONVERT(datetime, [Date], 103)) AS [Date]
FROM #Table2
GROUP BY RefId) AS t2
ON t1.RefId = t2.RefId

Sql server table has has month name as column, how to convert into multiple rows datewise [duplicate]

I have a scenario where I need to convert columns of table to rows
eg -
table - stocks:
ScripName ScripCode Price
-----------------------------------------
20 MICRONS 533022 39
I need to represent the table in the following format, but I just need this kind of representation for single row
ColName ColValue
-----------------------------
ScripName 20 MICRONS
ScripCode 533022
Price 39
so that I can directly bind the data to the datalist control.
Sound like you want to UNPIVOT
Sample from books online:
--Create the table and insert values as portrayed in the previous example.
CREATE TABLE pvt (VendorID int, Emp1 int, Emp2 int,
Emp3 int, Emp4 int, Emp5 int);
GO
INSERT INTO pvt VALUES (1,4,3,5,4,4);
INSERT INTO pvt VALUES (2,4,1,5,5,5);
INSERT INTO pvt VALUES (3,4,3,5,4,4);
INSERT INTO pvt VALUES (4,4,2,5,5,4);
INSERT INTO pvt VALUES (5,5,1,5,5,5);
GO
--Unpivot the table.
SELECT VendorID, Employee, Orders
FROM
(SELECT VendorID, Emp1, Emp2, Emp3, Emp4, Emp5
FROM pvt) p
UNPIVOT
(Orders FOR Employee IN
(Emp1, Emp2, Emp3, Emp4, Emp5)
)AS unpvt;
GO
Returns:
VendorID Employee Orders
---------- ---------- ------
1 Emp1 4
1 Emp2 3
1 Emp3 5
1 Emp4 4
1 Emp5 4
2 Emp1 4
2 Emp2 1
2 Emp3 5
2 Emp4 5
2 Emp5 5
see also: Unpivot SQL thingie and the unpivot tag
declare #T table (ScripName varchar(50), ScripCode varchar(50), Price int)
insert into #T values ('20 MICRONS', '533022', 39)
select
'ScripName' as ColName,
ScripName as ColValue
from #T
union all
select
'ScripCode' as ColName,
ScripCode as ColValue
from #T
union all
select
'Price' as ColName,
cast(Price as varchar(50)) as ColValue
from #T
select 'ScriptName', scriptName from table
union all
select 'ScriptCode', scriptCode from table
union all
select 'Price', price from table
As an alternative:
Using CROSS APPLY and VALUES performs this operation quite simply and efficiently with just a single pass of the table (unlike union queries that do one pass for every column)
SELECT
ca.ColName, ca.ColValue
FROM YOurTable
CROSS APPLY (
Values
('ScripName' , ScripName),
('ScripCode' , ScripCode),
('Price' , cast(Price as varchar(50)) )
) as CA (ColName, ColValue)
Personally I find this syntax easier than using unpivot.
NB: You must take care that all source columns are converted into compatible types for the single value column
DECLARE #TABLE TABLE
(RowNo INT,ScripName VARCHAR(10),ScripCode VARCHAR(10)
,Price VARCHAR(10))
INSERT INTO #TABLE VALUES
(1,'20 MICRONS ','533022','39')
SELECT ColumnName,ColumnValue from #Table
Unpivot(ColumnValue For ColumnName IN (ScripName,ScripCode,Price)) AS H
i solved the query this way
SELECT
ca.ID, ca.[Name]
FROM [Emp2]
CROSS APPLY (
Values
('ID' , cast(ID as varchar)),
('[Name]' , Name)
) as CA (ID, Name)
output look like
ID Name
------ --------------------------------------------------
ID 1
[Name] Joy
ID 2
[Name] jean
ID 4
[Name] paul
CREATE TABLE #ORIGINAL
(
COUNTRY VARCHAR(50),
MALE_CRICKETER VARCHAR(50),
FEMALE_CRICKETER VARCHAR(50),
MALE_STAR VARCHAR(50),
FEMALE_STAR VARCHAR(50),
)
select * from #ORIGINAL
SELECT COUNTRY, ca.GENDER, ca.STAR, ca.CRICKETR
FROM #ORIGINAL
CROSS APPLY (
Values
('M', MALE_CRICKETER, MALE_STAR),
('F', FEMALE_CRICKETER, FEMALE_STAR)
) as CA (GENDER, CRICKETR, STAR)

Update column with 4 consecutive purchases

I need to update my Result column values for the entire user to yes if the user did make 4 consecutive purchases without receiving a bonus in between. How can this be done. Please see my code below.....
-- drop table #Test
CREATE TABLE #Test (UserID int, TheType VARCHAR(10), TheDate DATETIME, Result VARCHAR(10))
INSERT INTO #Test
SELECT 1234, 'Bonus', GETDATE(), NULL
UNION
SELECT 1234, 'Purchase', GETDATE()-1, NULL
UNION
SELECT 1234, 'Purchase', GETDATE()-2, NULL
UNION
SELECT 1234, 'Purchase', GETDATE()-3, NULL
UNION
SELECT 1234, 'Purchase', GETDATE()-4, NULL
UNION
SELECT 1234, 'Bonus', GETDATE()-5, NULL
UNION
SELECT 1234, 'Purchase', GETDATE()-6, NULL
UNION
SELECT 1234, 'Bonus', GETDATE()-7, NULL
SELECT * FROM #Test ORDER BY TheDate
Again, please note that the purchases need to be consecutive (By TheDate)
You can as the below:
;WITH CTE1
AS
(
SELECT
ROW_NUMBER() OVER (ORDER BY TheDate) RowId,
ROW_NUMBER() OVER (PARTITION BY UserID,TheType ORDER BY TheDate) PurchaseRowId,
*
FROM #Test
), CTE2
AS
(
SELECT
MIN(A.RowId) MinId,
MAX(A.RowId) MaxId
FROM
CTE1 A
GROUP BY
A.TheType,
A.RowId - A.PurchaseRowId
)
SELECT
A.UserID ,
A.TheType ,
A.TheDate ,
CASE WHEN B.MinId IS NULL THEN NULL ELSE 'YES' END Result
FROM
CTE1 A LEFT JOIN
CTE2 B ON A.RowId >= B.MinId AND A.RowId <= B.MaxId AND (B.MaxId - B.MinId) > 2
--AND A.TheType = 'Purchase'
ORDER BY A.TheDate
Result:
UserID TheType TheDate Result
----------- ---------- ----------------------- - ------
1234 Bonus 2017-06-06 11:06:03.130 NULL
1234 Purchase 2017-06-07 11:06:03.130 NULL
1234 Bonus 2017-06-08 11:06:03.130 NULL
1234 Purchase 2017-06-09 11:06:03.130 YES
1234 Purchase 2017-06-10 11:06:03.130 YES
1234 Purchase 2017-06-11 11:06:03.130 YES
1234 Purchase 2017-06-12 11:06:03.130 YES
1234 Bonus 2017-06-13 11:06:03.130 NULL
First you have to derive the column group and then group by that (having = 4) and inner join with the original table.
drop table if exists #Test;
create table #Test
(
UserID int
, TheType varchar(10)
, TheDate date
, Result varchar(10)
);
insert into #Test
select 1234, 'Bonus', getdate(), null
union
select 1234, 'Purchase', getdate() - 1, null
union
select 1234, 'Purchase', getdate() - 2, null
union
select 1234, 'Purchase', getdate() - 3, null
union
select 1234, 'Purchase', getdate() - 4, null
union
select 1234, 'Bonus', getdate() - 5, null
union
select 1234, 'Purchase', getdate() - 6, null
union
select 1234, 'Bonus', getdate() - 7, null;
drop table if exists #temp;
select
*
, lag(t.TheDate, 1) over ( order by t.TheDate ) as Lag01
, lag(t.TheType, 1) over ( order by t.TheDate ) as LagType
into
#temp
from #Test t;
with cteHierarchy
as
(
select
UserID
, TheType
, TheDate
, Result
, Lag01
, t.TheDate as Root
from #temp t
where t.LagType <> t.TheType
union all
select
t.UserID
, t.TheType
, t.TheDate
, t.Result
, t.Lag01
, cte.Root as Root
from #temp t
inner join cteHierarchy cte on t.Lag01 = cte.TheDate
and t.TheType = cte.TheType
)
update test
set
Result = 4
from (
select
t.Root
, count(t.UserID) as Cnt
, t.UserID
from cteHierarchy t
group by t.UserID, t.Root
having count(t.UserID) = 4
) tt
inner join #Test test on tt.UserID = test.UserID
select * from #Test t
order by t.TheDate;

Getting the last row from a ROW_NUMBER using SQL

I am thinking there is a better way to grab the last row from a row_number instead of doing multiple nesting using T-SQL.
I need the total number of orders and the last ordered date. Say I have the following:
DECLARE #T TABLE (PERSON_ID INT, ORDER_DATE DATE)
INSERT INTO #T VALUES(1, '2016/01/01')
INSERT INTO #T VALUES(1, '2016/01/02')
INSERT INTO #T VALUES(1, '2016/01/03')
INSERT INTO #T VALUES(2, '2016/01/01')
INSERT INTO #T VALUES(2, '2016/01/02')
INSERT INTO #T VALUES(3, '2016/01/01')
INSERT INTO #T VALUES(3, '2016/01/02')
INSERT INTO #T VALUES(3, '2016/01/03')
INSERT INTO #T VALUES(3, '2016/01/04')
What I want is:
PERSON_ID ORDER_DATE ORDER_CNT
1 2016-01-03 3
2 2016-01-02 2
3 2016-01-04 4
Is there a better way to do this besides the following:
SELECT *
FROM (
SELECT *
, ROW_NUMBER() OVER (PARTITION BY PERSON_ID ORDER BY ORDER_CNT DESC) AS LAST_ROW
FROM (
SELECT *
, ROW_NUMBER () OVER (PARTITION BY PERSON_ID ORDER BY ORDER_DATE) AS ORDER_CNT
FROM #T
) AS A
) AS B
WHERE LAST_ROW = 1
Yes, you can use this:
SELECT
PERSON_ID,
MAX(ORDER_DATE) AS ORDER_DATE,
COUNT(*) AS ORDER_CNT
FROM #T
GROUP BY PERSON_ID
SELECT a.PERSON_ID
, a.ORDER_DATE
, a.ORDER_CNT
FROM
(
SELECT PERSON_ID
, ORDER_DATE
, rn = ROW_NUMBER () OVER (PARTITION BY PERSON_ID ORDER BY ORDER_DATE DESC)
, ORDER_CNT = COUNT(ORDER_DATE) OVER (PARTITION BY PERSON_ID)
FROM #T
) AS a
WHERE rn = 1
ORDER BY a.PERSON_ID;

Converting Columns into rows with their respective data in sql server

I have a scenario where I need to convert columns of table to rows
eg -
table - stocks:
ScripName ScripCode Price
-----------------------------------------
20 MICRONS 533022 39
I need to represent the table in the following format, but I just need this kind of representation for single row
ColName ColValue
-----------------------------
ScripName 20 MICRONS
ScripCode 533022
Price 39
so that I can directly bind the data to the datalist control.
Sound like you want to UNPIVOT
Sample from books online:
--Create the table and insert values as portrayed in the previous example.
CREATE TABLE pvt (VendorID int, Emp1 int, Emp2 int,
Emp3 int, Emp4 int, Emp5 int);
GO
INSERT INTO pvt VALUES (1,4,3,5,4,4);
INSERT INTO pvt VALUES (2,4,1,5,5,5);
INSERT INTO pvt VALUES (3,4,3,5,4,4);
INSERT INTO pvt VALUES (4,4,2,5,5,4);
INSERT INTO pvt VALUES (5,5,1,5,5,5);
GO
--Unpivot the table.
SELECT VendorID, Employee, Orders
FROM
(SELECT VendorID, Emp1, Emp2, Emp3, Emp4, Emp5
FROM pvt) p
UNPIVOT
(Orders FOR Employee IN
(Emp1, Emp2, Emp3, Emp4, Emp5)
)AS unpvt;
GO
Returns:
VendorID Employee Orders
---------- ---------- ------
1 Emp1 4
1 Emp2 3
1 Emp3 5
1 Emp4 4
1 Emp5 4
2 Emp1 4
2 Emp2 1
2 Emp3 5
2 Emp4 5
2 Emp5 5
see also: Unpivot SQL thingie and the unpivot tag
declare #T table (ScripName varchar(50), ScripCode varchar(50), Price int)
insert into #T values ('20 MICRONS', '533022', 39)
select
'ScripName' as ColName,
ScripName as ColValue
from #T
union all
select
'ScripCode' as ColName,
ScripCode as ColValue
from #T
union all
select
'Price' as ColName,
cast(Price as varchar(50)) as ColValue
from #T
select 'ScriptName', scriptName from table
union all
select 'ScriptCode', scriptCode from table
union all
select 'Price', price from table
As an alternative:
Using CROSS APPLY and VALUES performs this operation quite simply and efficiently with just a single pass of the table (unlike union queries that do one pass for every column)
SELECT
ca.ColName, ca.ColValue
FROM YOurTable
CROSS APPLY (
Values
('ScripName' , ScripName),
('ScripCode' , ScripCode),
('Price' , cast(Price as varchar(50)) )
) as CA (ColName, ColValue)
Personally I find this syntax easier than using unpivot.
NB: You must take care that all source columns are converted into compatible types for the single value column
DECLARE #TABLE TABLE
(RowNo INT,ScripName VARCHAR(10),ScripCode VARCHAR(10)
,Price VARCHAR(10))
INSERT INTO #TABLE VALUES
(1,'20 MICRONS ','533022','39')
SELECT ColumnName,ColumnValue from #Table
Unpivot(ColumnValue For ColumnName IN (ScripName,ScripCode,Price)) AS H
i solved the query this way
SELECT
ca.ID, ca.[Name]
FROM [Emp2]
CROSS APPLY (
Values
('ID' , cast(ID as varchar)),
('[Name]' , Name)
) as CA (ID, Name)
output look like
ID Name
------ --------------------------------------------------
ID 1
[Name] Joy
ID 2
[Name] jean
ID 4
[Name] paul
CREATE TABLE #ORIGINAL
(
COUNTRY VARCHAR(50),
MALE_CRICKETER VARCHAR(50),
FEMALE_CRICKETER VARCHAR(50),
MALE_STAR VARCHAR(50),
FEMALE_STAR VARCHAR(50),
)
select * from #ORIGINAL
SELECT COUNTRY, ca.GENDER, ca.STAR, ca.CRICKETR
FROM #ORIGINAL
CROSS APPLY (
Values
('M', MALE_CRICKETER, MALE_STAR),
('F', FEMALE_CRICKETER, FEMALE_STAR)
) as CA (GENDER, CRICKETR, STAR)

Resources