Output different columns from 2 Select Statements - sql-server

I want to achieve something like;
eg.
ID VALUE NAME
1 1234 COUNTER
2 1235 BAGGAGE
OUTPUT:
COUNTER BAGGAGE
1234 1235
Script:
SELECT ID, VALUE, NAME FROM table WHERE ID = 1
UNION ALL
SELECT ID, VALUE, NAME FROM table WHERE ID = 2
RESULT:
ID VALUE NAME
1 1234 COUNTER
2 1235 BAGGAGE
Is this a row to column approach?

Another one standard solution
select max(case when name='counter' then value end) as counter,
max(case when name='baggage' then value end) as baggage
from table

In this case, you use the query below. It's not very generic but may be sufficient in specific cases as is simple and easy to use.
select
(select top 1 value from yourtable where name = 'counter') as counter,
(select top 1 value from yourtable where name = 'baggage') as baggage
SQL Fiddle demo

try this::
select id,case when name='counter' then value else ' ' end as counter,
case when name='baggage' then value else ' ' end as baggage
from table
it outputs
id counter baggage
1 1234
2 1235
fiddle demo

You could use a PIVOT like this:
DECLARE #DataSource TABLE
(
[ID] TINYINT
,[VALUE] SMALLINT
,[Name] VARCHAR(12)
)
INSERT INTO #DataSource ([ID],[VALUE],[Name])
VALUES (1,1234,'COUNTER')
,(2,1235,'BAGGAGE')
SELECT [COUNTER]
,[BAGGAGE]
FROM
(
SELECT [VALUE]
,[Name]
FROM #DataSource
) AS DS
PIVOT
(
MAX([VALUE]) FOR [Name] IN ([COUNTER], [BAGGAGE])
) AS PVT
OUTPUT:
Check the example.

Related

parent id hierarchy identification MS SqlServer2012

I have this code
create table #temp
(
order_id int not null identity(1,1) primary key
,sid int
,created_date date
,parent_order_id int
)
insert into #temp
(
sid
,created_date
)values(1,'2017-01-01')
insert into #temp
(
sid
,created_date
,parent_order_id
)values(1,'2017-02-01',1),(1,'2017-03-01',2),(1,'2017-04-01',3)
insert into #temp
(
sid
,created_date
)values(1,'2017-06-01')
insert into #temp
(
sid
,created_date
,parent_order_id
)values(1,'2017-07-01',5),(1,'2017-08-01',6)
select * from #temp
Whenever parent_order_id is null which indicates it is a new order. After that customer can add items associated to that order. so we have parent_order_id filled for these associations. But I want to know what is the first order_id for each association child order.I am looking for an output like below.
`order_id sid created_date parent_order_id original_order_id
1 1 2017-01-01 NULL 1
2 1 2017-02-01 1 1
3 1 2017-03-01 2 1
4 1 2017-04-01 3 1
5 1 2017-06-01 NULL 4
6 1 2017-07-01 5 4
7 1 2017-08-01 6 4
`
any help is appreciated. Thanks in advance.
With the following piece of code you can get results you are expecting.
;WITH cte (order_id, original_order_id)
AS
(
SELECT order_id, order_id AS original_order_id
FROM #temp WHERE parent_order_id IS NULL
UNION ALL
SELECT o.order_id AS order_id, cte.original_order_id AS original_order_id
FROM #temp AS o
JOIN cte
ON o.parent_order_id = cte.order_id
)
SELECT #temp.order_id, #temp.sid, #temp.created_date, #temp.parent_order_id, cte.original_order_id
FROM #temp
JOIN cte ON cte.order_id=#temp.order_id
ORDER BY cte.order_id
Please be aware, that there are certain limits on recursion as this for CTE. Currently it is 100 which can be pushed up to 32767.

Converting rows to columns

I have a query with the columns 'Name', 'Amount', and 'ReasonId'. I want to sum the amount and put the reasons on one row to keep every name to a single line. There are about 50 distinct ReasonId's so I do not want to name the column the name of the ReasonId's. Instead, I would like to name the columns 'Reason1', 'Reason2', 'Reason3', and 'Reason4'. One single name can have up to 4 different reasons.
I have this:
Name Amount ReasonId
-------------------------
Bob $5 7
Bob $8 6
John $2 8
John $5 9
John $3 9
John $8 4
I want to produce the following:
Name Amount Reason1 Reason2 Reason3 Reason4
-----------------------------------------------------
Bob $13 7 6 NULL NULL
John $18 8 9 4 NULL
One way to do this is to use the dense_rank window function to number the rows, and then use conditional aggregation to put the reason in the correct columns.
I can't see anything that would give the specific order of the reason columns though, maybe there is some column missing that provides the order?
with cte as (
select
name,
reasonid,
amount,
dense_rank() over (partition by name order by reasonid) rn
from your_table
)
select
name,
sum(amount) amount,
max(case when rn = 1 then reasonid end) reason1,
max(case when rn = 2 then reasonid end) reason2,
max(case when rn = 3 then reasonid end) reason3,
max(case when rn = 4 then reasonid end) reason4
from cte
group by name
If you have some column that gives the order you want then change the order by clause used in the dense_rank function.
Sample SQL Fiddle (using PG as MSSQL seems to be offline).
The output from the query above would be:
| name | amount | reason1 | reason2 | reason3 | reason4 |
|------|--------|---------|---------|---------|---------|
| Bob | 13 | 6 | 7 | (null) | (null) |
| John | 18 | 4 | 8 | 9 | (null) |
You could also use a pivot to achieve this; if you know the columns you can enter them in the script, but if not, you can use dynamic sql (there are reasons why you might want to avoid the dynamic solution).
The advantage of this route is that you can enter the column list in a table and then changes to that table will result in changes to your output with change to the script involved. The disadvantages are all those associated with dynamic SQL.
In the interests of variation, here is a dynamic SQL solution using temp tables to hold your data, since a different possibility has been provided:
-- set up your data
CREATE TABLE #MyTab (Name VARCHAR(4), Amount INT, ReasonId INT)
CREATE TABLE #AllPossibleReasons (Id INT,Label VARCHAR(10))
INSERT #AllPossibleReasons
VALUES
(1,'Reason1')
,(2,'Reason2')
,(3,'Reason3')
,(4,'Reason4')
,(5,'Reason5')
,(6,'Reason6')
,(7,'Reason7')
,(8,'Reason8')
,(9,'Reason9')
INSERT #MyTab
VALUES
('Bob',7,7)
,('Bob',8,6)
,('John',2,8)
,('John',5,9)
,('John',3,9)
,('John',8,4)
-----------------------------------------------------------------------------
-- The actual query
DECLARE #ReasonList VARCHAR(MAX) = ''
DECLARE #SQL VARCHAR(MAX)
SELECT #ReasonList = #ReasonList + ',' + QUOTENAME(Label)
FROM #AllPossibleReasons
SET #ReasonList = SUBSTRING(#ReasonList,2,LEN(#ReasonList))
SET #SQL =
'SELECT Name,Value,' + #ReasonList + ' FROM
(SELECT
M.Name,SUM(Amount) AS This, Label, SUM(Total.Value) AS Value
FROM
#MyTab AS M
INNER JOIN #AllPossibleReasons AS Reason ON M.ReasonId = Reason.Id
INNER JOIN(SELECT T.Name, SUM(Amount)Value
FROM #MyTab T GROUP BY T.Name) AS Total ON M.Name = Total.Name
GROUP BY M.Name, Reason.Label) AS Up
PIVOT (SUM(THis) FOR Label IN (' + #ReasonList + ')) AS Pvt'
EXEC (#SQL)
DROP TABLE #AllPossibleReasons
DROP TABLE #MyTab
Working from the information in ListAGG in SQLSERVER, I came up with this somewhat ugly example:
with tbl1 as (
-- Set up initial data set
select 'Bob' name, 5 amount, 7 ReasonId
union all select 'Bob' , 3, 4
union all select 'Bob', 2, 1
union all select 'Brian', 8, 2
union all select 'Bob', 6, 4
union all select 'Brian', 1, 3
union all select 'Tim', 2, 2)
, TBL2 AS ( -- Add a blank to separate the concatenation
SELECT NAME
, AMOUNT
, CAST(ReasonId as varchar) + ' ' ReasonId from tbl1
)
select ta.name
, Total
, ReasonIds from (
(select distinct name, stuff((select distinct '' + t2.ReasonId from tbl2 t2
where t1.name = t2.name
for xml path(''), type).value('.','NVARCHAR(MAX)'),1,0,' ') ReasonIds from tbl2 t1) ta
inner join ( select name, sum(amount) Total from tbl1 group by name) tb on ta.name = tb.name) ;
This converts TBL1 to the following:
name Total ReasonIds
Bob 16 1 4 7
Brian 9 2 3
Tim 2 2

Group by count once

My data is like below:
ClassId ClassName StudentId Subject SubjectId
-----------------------------------------------------
1 ESL 12 English 20
1 ESL 13 Science 30
1 ESL 12 Social 40
1 ESL 12 Maths 50
Required output: parameters are Subject column values
ClassId ClassName TotalStudents SubjectIds
-----------------------------------------------
1 ESL 2 20, 40, 50, 30
When one student takes multiple subjects then count student only once, so in the above data 12 is one student id takes multiple subjects so counted only once. TotalStudents value is 2 (1 from student id 12 and 1 from student id 13)
I am not looking for how to display subjectIds column value in comma separated string.
Thanks in advance
COUNT DISTINCT then use STUFF for combined the subject
declare #temp table
(ClassId int,ClassName nvarchar(max),StudentId int,Subject nvarchar(max), SubjectId int)
insert into #temp values (1,'ESL',12,'English' , 20 )
insert into #temp values (1,'ESL',13,'Science' , 30 )
insert into #temp values (1,'ESL',12,'Social ' , 40 )
insert into #temp values (1,'ESL',12,'Maths ' , 50 )
select ClassId,ClassName,COUNT(DISTINCT StudentId) CNT,
STUFF( (SELECT ',' + CAST(t1.SubjectId AS NVARCHAR)
FROM #temp t1
WHERE StudentId = t1.StudentId
FOR XML PATH('')),
1, 1, '') SubjectIdS
from #temp
GROUP BY ClassId,ClassName
OUTPUT
DISTINCT can be applied inside aggregate functions.
SELECT COUNT(DISTINCT column_name) FROM table_name;
If you don't need to display the SubjectIds, then you need to use a GROUP BY clause to group the resultset by ClassId and ClassName.
SELECT ClassId, ClassName, COUNT(distinct StudentId) as TotalStudents
FROM MyTable
GROUP BY ClassId, ClassName
See this example at SqlFiddle

how to join 2 tables but have the same result count as table a

here is the dilemma i am having...
i have 2 tables
create table #orders
(orderNumber int,qty int,sku varchar(250),barcode varchar(250))
create table #allItemsInBox
([id] int,[date] date,[localsku] varchar(250),[box] varchar(250),barcode varchar(250))
i need to join the 2 tables on [barcode] and only have 1 result in the final table for every row in #allItemsInBox
please note [#allItemsInBox].[id] is unique the other fields in [#allItemsInBox] may not be
how would i go about doing something like this?
sample data:
[#orders]
(1,0,'10','10')
(1,0,'20','20')
(3,0,'20','20')
(4,0,'30','30')
(5,0,'40','40')
(6,0,'50','50')
#allItemsInBox
(1,'12/3/2014',10,'Box1',10)
(2,'12/2/2014',20,'Box2',20)
(3,'12/1/2014',20,'Box3',20)
(4,'11/30/2014',20,'Box4',20)
(5,'11/29/2014',30,'Box5',30)
(6,'11/28/2014',40,'Box6',40)
(7,'11/27/2014',60,'Box8',60)
(8,'11/27/2014',50,'Box10',50)
#output
(ordernumber int,uniqueitemID int,localsku varchar(250),box varchar(250))
(1,1,10,'Box1')
(1,2,20,'Box2')
(3,3,10,'Box3')
(4,5,30,'Box5')
(5,6,40,'Box6')
(6,8,50,'Box10')
This is quick but works. Depending on the size of your data this might be not the best way performance wise. But this will give you a start
DECLARE #orders TABLE (
orderNumber int,
qty int,
sku varchar(250),
barcode varchar(250)
)
DECLARE #allItemsInBox TABLE (
[id] int,
[date] date,
[localsku] varchar(250),
[box] varchar(250),
barcode varchar(250)
)
INSERT INTO #orders VALUES
(1,0,'10','10'),
(1,0,'20','20'),
(3,0,'20','20'),
(4,0,'30','30'),
(5,0,'40','40'),
(6,0,'50','50')
INSERT INTO #allItemsInBox VALUES
(1,'2014-12-03',10,'Box1',10),
(2,'2014-12-02',20,'Box2',20),
(3,'2014-12-01',20,'Box3',20),
(4,'2014-11-30',20,'Box4',20),
(5,'2014-11-29',30,'Box5',30),
(6,'2014-11-28',40,'Box6',40),
(7,'2014-11-27',60,'Box8',60),
(8,'2014-11-27',50,'Box10',50)
SELECT
orders.orderNumber AS ordernumber
,(SELECT TOP 1 allItems.id FROM #allItemsInBox allItems WHERE allItems.barcode = orders.barcode AND allItems.id >= orders.orderNumber ORDER BY allItems.id) AS uniqueitemID
,(SELECT TOP 1 allItems.localsku FROM #allItemsInBox allItems WHERE allItems.barcode = orders.barcode AND allItems.id >= orders.orderNumber ORDER BY allItems.id) AS localsku
,(SELECT TOP 1 allItems.box FROM #allItemsInBox allItems WHERE allItems.barcode = orders.barcode AND allItems.id >= orders.orderNumber ORDER BY allItems.id) AS box
FROM
#orders orders
Results in:
ordernumber uniqueitemID localsku box
1 1 10 Box1
1 2 20 Box2
3 3 20 Box3
4 5 30 Box5
5 6 40 Box6
6 8 50 Box10
edit: I updated the answer. You now have the same output as you specified in your example/question

SQL-SERVER Get Result from table where Value like 1-9

I have a table WHERE there's a column that has QTY Ranges like 1-5, 6-9 etc and prices in another column. i.e
Price QTY
------------------------
Price Qty Range
----- ----------
45 1-5
35 6-9
30 10-18
Now I want to get the result from the table where Qty is 7 Therefore Price returned should be 35 ( since Qty 7 falls in range 6-9
Any help greatly appriciated
Try this :-
Declare #val int
Set #val=7
;with cte(price,startVal,endVal) as
( Select price,
parsename(replace([Qty Range],'-','.'),2),
parsename(replace([Qty Range],'-','.'),1)
from yourTable
)
Select Price from cte
where #val between startVal and endVal
Result : 35
Demo in SQL FIDDLE
If you can't redesign the table to be sane, you can use a couple of CTEs to reconstruct it as a sane table for this query:
declare #PriceRanges table (Price int,QtyRange varchar(20))
insert into #PriceRanges (Price,QtyRange) values
(45,'1-5'),
(35,'6-9'),
(30,'10-18')
declare #Search int
set #Search = 7
;with FoundDashes as (
select Price,QtyRange,CHARINDEX('-',QtyRange) as DashPos
from #PriceRanges
)
, SaneRanges as (
select Price,CONVERT(int,SUBSTRING(QtyRange,1,DashPos-1)) as LowRange,CONVERT(int,SUBSTRING(QtyRange,DashPos+1,8000)) as HighRange
from FoundDashes
)
select Price from SaneRanges where #Search between LowRange and HighRange
Produces 35 as a result.

Resources