I have three tables:
__Person__ __Hat__ __Shoe__
ID int ID int ID int
Name nvarchar Name nvarchar Name nvarchar
HatID int
ShoeID int
Here's some sample data of the tables:
________________Person_________________
-ID- -Name- -HatID- -ShoeID-
1 Anna 1 2
2 Nina 2 3
3 Lola 3 NULL
______Hat_______
-ID- -Name-
1 Blue
2 Red
3 Green
______Shoe_______
-ID- -Name-
1 Boot
2 Heels
3 Sport
I have a query like this:
SELECT Person.ID, Person.Name, Hat.Name, Shoe.Name
FROM Person
INNER JOIN Hat ON Person.HatID = Hat.ID
JOIN JOIN Shoe ON Person.Shoe = Shoe.ID
This query returns the following results:
-PersonID- -PersonName- -HatName- -ShoeName-
1 Anna Blue Heels
2 Nina Red Sport
3 Lola Green NULL
I want to give PersonName, HatName and ShoeName order numbers 1, 2, 3. I need results like this:
-PersonID- -OrderNumber- -Value-
1 1 Anna
1 2 Blue
1 3 Heels
2 1 Nina
2 2 Red
2 3 Sport
3 1 Lola
3 2 Green
3 3 NULL
How should I write the query to return this results?
You can use UNPIVOT here:
DECLARE #Persons TABLE
(
ID INT ,
Name NVARCHAR(20) ,
HatID INT ,
ShoeID INT
)
DECLARE #Hats TABLE ( ID INT, Name NVARCHAR(20) )
DECLARE #Shoes TABLE ( ID INT, Name NVARCHAR(20) )
INSERT INTO #Persons
VALUES ( 1, 'Anna', 1, 2 ),
( 2, 'Nina', 2, 3 ),
( 3, 'Lola', 3, NULL )
INSERT INTO #Hats
VALUES ( 1, 'Blue' ),
( 2, 'Red' ),
( 3, 'Green' )
INSERT INTO #Shoes
VALUES ( 1, 'Boot' ),
( 2, 'Heels' ),
( 3, 'Sport' );
WITH cte
AS ( SELECT p.ID ,
p.Name AS PersonName ,
h.Name AS HatName ,
ISNULL(s.Name, '') AS ShoeName
FROM #Persons p
INNER JOIN #Hats h ON p.HatID = h.ID
LEFT JOIN #Shoes s ON p.ShoeID = s.ID
)
SELECT ID AS PersonID ,
ROW_NUMBER() OVER ( PARTITION BY ID ORDER BY ( SELECT
1
) ) AS OrderNumber ,
IIF(Value = '', NULL, Value) AS Value
FROM cte UNPIVOT( Value FOR v IN ( [PersonName], [HatName], [ShoeName] ) ) u;
Output:
PersonID OrderNumber Value
1 1 Anna
1 2 Blue
1 3 Heels
2 1 Nina
2 2 Red
2 3 Sport
3 1 Lola
3 2 Green
3 3 NULL
try this:
SELECT Person.ID, 1 OrderNumber, Person.Name
FROM Person
UNION ALL
SELECT Person.ID, 2 OrderNumber, Hat.Name
FROM Person
LEFT JOIN JOIN Hat ON Person.HatID = Hat.ID
UNION ALL
SELECT Person.ID, 3 OrderNumber, Shoe.Name
FROM Person
LEFT JOIN JOIN Shoe ON Person.ShoeID = Shoe.ID
ORDER BY 1,2
Related
Input:
ID COLUMN1 COLUMN2 COLUMN3
1 M,S,E,T 1,2,3,4 5,6,7
2 A,B,C 6,5,8,7,9,1 2,4,3,0,1
Output:
ID COLUMN1 COLUMN2 COLUMN3
1 M 10 50
1 S 20 60
1 E 30 70
1 T 40 NULL
2 A 6 2
2 B 5 4
2 C 8 3
2 NULL 7 0
2 NULL 9 1
2 NULL 1 NULL
Code:
select ID,
array_index( COLUMN1_arr, n ) as COLUMN1,
array_index( COLUMN2_arr, n ) as COLUMN2
from sample
lateral view numeric_range(size(COLUMN1_arr)) n1 as n;
Error:
FAILED: Semantic Exception [Error 10011]: Invalid function array_index
Here I'm having a multiple values in single column i need to convert it to rows as mentioned Output.
Explode Is an UDTF provided in hive you can use the same to split data from columns into rows.
SELECT ID1, col1,col2,col3
FROM tableName
lateral view explode(split(COLUMN1,',')) cols1 AS col1
lateral view explode(split(COLUMN2,',')) cols2 AS col2
lateral view explode(split(COLUMN3,',')) cols3 AS col3
Plain vanilla hive solution, without brickhouse UDFs.
Demo:
with
input as ( ---------------Input dataset
select stack(2,
1, array('M','S','E','T'), array(1,2,3,4), array(5,6,7),
2, array('A','B','C'), array(6,5,8,7,9,1), array( 2,4,3,0,1)
) as (ID,COLUMN1,COLUMN2,COLUMN3)
),
--explode each array and FULL join them
c1 as (
select i.id, v.column1, p
from input i
lateral view posexplode(i.COLUMN1) v as p,column1
),
c2 as (
select i.id, v.column2, p
from input i
lateral view posexplode(i.COLUMN2) v as p,column2
),
c3 as (
select i.id, v.column3, p
from input i
lateral view posexplode(i.COLUMN3) v as p,column3
)
--FULL JOIN
select coalesce(c1.id,c2.id,c3.id) id, c1.column1, c2.column2, c3.column3
from c1
full join c2 on c1.id=c2.id and c1.p=c2.p
full join c3 on nvl(c1.id,c2.id)=c3.id and nvl(c1.p,c2.p)=c3.p --note NVL usage
;
Result:
OK
id column1 column2 column3
1 M 1 5
1 S 2 6
1 E 3 7
1 T 4 NULL
2 A 6 2
2 B 5 4
2 C 8 3
2 NULL 7 0
2 NULL 9 1
2 NULL 1 NULL
I have the following sample data:
ID | SectionID | LocID
1 32 12
1 32 2
1 32 2
1 34 3
1 34 4
2 36 8
2 36 9
2 37 8
2 37 9
2 37 4
The output should be grouped by ID. The Count LocID field should show the
number of DISTINCT LocIDs per sectionID totaled together.
For ID of 1, we have 2 distinct LocID for SectionID 32 and 2 for SectionID 34. Totaled equals 4
For ID of 2, we have 2 distinct LocID for SectionID 36 and 3 for sectionID 37. Total equals 5
Result:
ID Count
1 4
2 5
I did a group by ID but not sure how to do further grouping based on what I need. I am using SQL Server 2016.
The easiest way, I think, is to group by your ID and do some kind of count distinct on a concatenation of SectionID and LocID. If these are character data, you can get away with just concatenating with some kind of delimiter. If their numeric, you can do something like the example below, or convert them to strings and concat with a delimiter.
-------------------------
-- set up sample data
-------------------------
declare #datatable as table(ID int, SectionID int, LocID int)
insert into #datatable(ID, SectionID, LocID) VALUES
(1,32,12 ),
(1,32,2 ),
(1,32,2 ),
(1,34,3 ),
(1,34,4 ),
(2,36,8 ),
(2,36,9 ),
(2,37,8 ),
(2,37,9 ),
(2,37,4 )
-------------------------
-- The query
-------------------------
SELECT
ID
,COUNT (DISTINCT SectionID * 10000 + LocID)
FROM
#datatable
GROUP BY ID
Gives the result:
(10 row(s) affected)
ID
----------- -----------
1 4
2 5
(2 row(s) affected)
You could use a nested group by, such as
SELECT ID, SUM([Count])
FROM
(
SELECT ID, SectionID, COUNT(DISTINCT LocID) AS [Count]
FROM Table
GROUP BY ID, SectionID
) Q
GROUP BY ID
A down and dirty way is to just nest your groupings.
DECLARE #t TABLE
(
ID INT,
SectionID INT,
LocID INT
);
INSERT INTO #t
(
ID
,SectionID
,LocID
)
VALUES
( 1,32,12),
( 1,32,2),
( 1,32,2),
( 1,34,3),
( 1,34,4),
( 2,36,8),
( 2,36,9),
( 2,37,8),
( 2,37,9),
( 2,37,4)
SELECT
d.ID
,SUM(d.LocIDs) AS LocIDCnt
FROM
(
SELECT
ID
,SectionID
,COUNT(DISTINCT LocID) AS LocIDs
FROM
#t
GROUP BY
ID
,SectionID
) AS d
GROUP BY
d.ID;
Result set:
+----+-------+
| ID | Count |
+----+-------+
| 1 | 4 |
| 2 | 5 |
+----+-------+
One more way:
select ID, COUNT(*) as SecLocCount
from (
select distinct ID, SectionID, LocID from [MyTable]
) AS distinctRows
group by ID
Let's say I have the following table tbl_Rules:
RuleID NameOperator NameValues TypeOperator TypeValue
1 NotIn John In 2
1 NotIn Alex In NULL
1 NotIn Mike In NULL
2 In Mike NotIn 2
And my source table looks like this tbl_Source:
ID Name Type Cost
1 Mike 2 100
2 Cole 2 200
3 Ken 1 300
4 Tara 1 400
5 Mike 1 500
6 Sonya 1 600
7 Ann 2 700
8 Mike 1 800
I want to be able to join these two tables and get the following result tbl_Result:
RuleID Name Type Cost
1 Cole 2 200
1 Ann 2 700
2 Mike 1 500
2 Mike 1 800
If I was writing this query manually my query would look like this:
select 1, Name, Type, Cost
from tbl_Source
Where Name not in ('John', 'Alex', 'Mike') and Type in (2)
union all
select 2, Name, Type, Cost
from tbl_Source
where Name in ('Mike') and Type not in (2)
In my current setup tbl_Rule has 500 records and tbl_Source has 500k records.
Any advice on this can be achieved is greatly appreciated. Limitations:
No CLR functions, No 2017 features (e.g. String_agg)
Update: DDL statements for the above sample can be found here: http://sqlfiddle.com/#!18/9a29f/2/0
Here's one way. I have used cross join to check the rules. There may be better ways with dynamic SQL where rules are implemented in join
declare #tbl_Rules table(
RuleID int
, NameOperator varchar(20)
, NameValues varchar(20)
, TypeOperator varchar(20)
, TypeValue int
)
insert into #tbl_Rules
values
(1, 'NotIn', 'John', 'In', 2)
, (1, 'NotIn', 'Alex', 'In', NULL)
, (1, 'NotIn', 'Mike', 'In', NULL)
, (2, 'In', 'Mike', 'NotIn', 2)
declare #tbl_Source table (
ID int
, Name varchar(20)
, Type int
, Cost int
)
insert into #tbl_Source
values
(1, 'Mike', 2, 100)
, (2, 'Cole', 2, 200)
, (3, 'Ken', 1, 300)
, (4, 'Tara', 1, 400)
, (5, 'Mike', 1, 500)
, (6, 'Sonya', 1, 600)
, (7, 'Ann', 2, 700)
, (8, 'Mike', 1, 800)
;with cte as (
select
distinct Ruleid, a.NameOperator, a.TypeOperator
, NameValues = (
select
'!' + b.NameValues
from
#tbl_Rules b
where
a.RuleID = b.RuleID
and b.NameValues is not null
for xml path('')
) + '!'
, TypeValue = (
select
concat('!', b.TypeValue)
from
#tbl_Rules b
where
a.RuleID = b.RuleID
and b.TypeValue is not null
for xml path('')
) + '!'
from
#tbl_Rules a
)
select
b.RuleID, a.Name, a.Type, a.Cost
from
#tbl_Source a
cross join cte b
where
1 = case
when b.NameOperator = 'In' and charindex('!' + a.Name + '!', b.NameValues) > 0 and b.TypeOperator = 'In' and charindex(concat('!', a.Type, '!'), b.TypeValue) > 0 then 1
when b.NameOperator = 'In' and charindex('!' + a.Name + '!', b.NameValues) > 0 and b.TypeOperator = 'Notin' and charindex(concat('!', a.Type, '!'), b.TypeValue) = 0 then 1
when b.NameOperator = 'NotIn' and charindex('!' + a.Name + '!', b.NameValues) = 0 and b.TypeOperator = 'In' and charindex(concat('!', a.Type, '!'), b.TypeValue) > 0 then 1
when b.NameOperator = 'NotIn' and charindex('!' + a.Name + '!', b.NameValues) = 0 and b.TypeOperator = 'NotIn' and charindex(concat('!', a.Type, '!'), b.TypeValue) = 0 then 1
else 0
end
Output:
RuleID Name Type Cost
---------------------------
1 Cole 2 200
1 Ann 2 700
2 Mike 1 500
2 Mike 1 800
You can try this.
SELECT MAX(R_N.RuleID) RuleID, S.Name, S.Type, S.Cost
FROM tbl_Source S
INNER JOIN tbl_Rules R_N ON
(R_N.NameValues <> S.Name and R_N.NameOperator = 'NotIn' )
OR (R_N.NameValues = S.Name and R_N.NameOperator = 'In' )
INNER JOIN tbl_Rules R_S ON
R_S.RuleID = R_N.RuleID AND
(R_S.TypeValue <> S.Type and R_S.TypeOperator = 'NotIn' )
OR (R_S.TypeValue = S.Type and R_S.TypeOperator = 'In' )
GROUP BY
S.Name, S.Type, S.Cost
HAVING
MAX(R_N.NameOperator) = MIN(R_N.NameOperator)
AND MAX(R_S.TypeOperator) = MIN(R_S.TypeOperator)
Result:
RuleID Name Type Cost
----------- -------------------- ----------- -----------
1 Ann 2 700
1 Cole 2 200
2 Mike 1 500
2 Mike 1 800
I am working on SQL, I have two tables
EId Ename
1 john
2 alex
3 piers
4 sara
And the second table is
PID PNAME EID
1 mcndd 1
2 carter 1
3 leare 2
4 jain 2
The result should be
EID count PID
1 2 1
1 2 2
2 2 3
2 2 4
I want a query for this.i had tried like this
SELECT t1.EID, COUNT(t1.EID) count,PID
from Employertable t1
INNER JOIN persontable P ON P.EID=t1.EID
Group By t1.EID Having Count(T1.EID) > 1
You can do this using window functions. With those functions you can combine aggregated data with non-aggregated data:
DECLARE #t1 TABLE ( EID INT )
DECLARE #t2 TABLE ( PID INT, EID INT )
INSERT INTO #t1
VALUES ( 1 ),
( 2 ),
( 3 ),
( 4 )
INSERT INTO #t2
VALUES ( 1, 1 ),
( 2, 1 ),
( 3, 2 ),
( 4, 2 )
SELECT *
FROM ( SELECT t1.EID ,
COUNT(*) OVER ( PARTITION BY t2.EID ) AS C ,
t2.PID
FROM #t1 t1
JOIN #t2 t2 ON t2.EID = t1.EID
) t
WHERE t.C > 1
Output:
EID C PID
1 2 1
1 2 2
2 2 3
2 2 4
i am using sql server 2008, in which i have some trouble i can not find one column
TblMaster
ID Name City
1 Hiren Juanagadh
2 Ashish Gandhinagar
2 Mayur Ahmedabad
3 Hitesh Junagadh
4 Nipun Ahmedabad
4 Vivek Rajkot
4 Samir Surat
5 Sagar Vadodara
Now i want Anoter column CountId so i want output like below
TblMaster
ID Name City CountId
1 Hiren Juanagadh 0
2 Ashish Gandhinagar 2
2 Mayur Ahmedabad 2
3 Hitesh Junagadh 0
4 Nipun Ahmedabad 3
4 Vivek Rajkot 3
4 Samir Surat 3
5 Sagar Vadodara 0
Means if Id column only one then CountId = 0
If Id column more than one then CountId = Count of Idcolumn
Prepare table
declare #T table (
id int,
Name nvarchar(6),
City nvarchar(20))
insert #T values
( 1 , 'Hiren', 'Juanagadh'),
( 2 , 'Ashish', 'Gandhinagar'),
( 2 , 'Mayur', 'Ahmedabad'),
( 3 , 'Hitesh', 'Junagadh'),
( 4 , 'Nipun', 'Ahmedabad'),
( 4 , 'Vivek', 'Rajkot'),
( 4 , 'Samir', 'Surat'),
( 5 , 'Sagar', 'Vadodara')
Select statement
without 1->0 correction
SELECT *, CountID = count(*) over (Partition by ID)
from #T
with 1->0 correction
select id, Name,City,CountID = case when CountID = 1 then 0 else CountID end
from (
SELECT *, CountID = count(*) over (Partition by ID)
from #T )
RES
Try this query:::
select *,(case when (select count(id) from TblMaster )=1
then 0 else (select count(id) from TblMaster) end) as count
from tblmaster