How to return 1 row instead of 3 when one column has different data - sql

I have 3 rows of data returned from a query
OrderId | OtherId
--------+---------
1234 | 444
1234 | 555
1234 | 666
How to return data in this format
OrderId | OtherId | OtherId2 | OtherId
--------+---------+----------+--------
1234 | 444 | 555 | 666
Can I use Distinct for this problem?
EDIT
The result set comes from a query such as
left join (
Select distinct
o.id
,OL2.db
,case
when i.cust = 'cust2' then
case
when
lower(pdf.dept) not like 'abc%' or pdf.dept is null
then 'Yes'
else'No'
end
else 'Yes'
end as 'Show'
,otherId
from order o with(nolock)
Join instance i with(nolock) on i.id = o.id
Join orderLine ol with(nolock) on ol.id = o.SocialNetworker_Order_InstanceId
and ol.id = o.id
join product p with(nolock) on o.id = p.id
and ol.id = p.id
left join productEx pdf with(nolock) on p.id = pdf.id
and o.id = pdf.id
Where i.cust in ('cust1')
) ol2 on OL2.id = sno.id
and OL2.id2 = sno.id2
and i.db = cc.db
How to work solution into the above code?

You can use row_number() and conditional aggregation:
select orderid,
max(case when seqnum = 1 then otherid end) as otherid_1,
max(case when seqnum = 2 then otherid end) as otherid_2,
max(case when seqnum = 3 then otherid end) as otherid_3
from (select t.*, row_number() over (partition by orderid order by otherid) as seqnum
from t
) t
group by orderid;

Use an outer join with cascading join conditions:
select t1.OrderId, t1.OtherId OtherId1, t2.OtherId OtherId2, t3.OtherId OtherId3
from orders t1
left join orders t2 on t2.OrderId = t1.OrderId
and t2.OtherId > t1.OtherId
left join orders t3 on t3.OrderId = t2.OrderId
and t3.OtherId > t2.OtherId
If there are less than 3 other ids, the right-most columns will be null.
This query will work on pretty much any database.

Related

Create table with values from one column and another column without intersection

I have a table like so:
userid | clothesid
-------|-----------
1 | 1
1 | 3
2 | 1
2 | 4
2 | 5
What I want from this table is a table like so:
userid | clothesid
-------|-----------
1 | 4
1 | 5
2 | 3
How can I do this?
I've tried it with one entry as:
select distinct r.clothesid from table r where r.clothes not in (select r1.clothes from table r1 where r1.userid=1);
and this returns 4,5, but I'm not sure where to proceed from here
You can cross join the list of userids and the list of clothesid to generate all combinations, and then use not exists on the original table to identify the missing rows:
select u.userid, c.clothesid
from (select distinct userid from mytable) u
cross join (select distinct clothesid from mytable) c
where not exists(
select 1 from mytable t on t.userid = u.userid and t.clothesid = c.clothesid
)
I think you want:
select (case when t1.clothesid is not null then 2 else 1 end),
coalesce(t1.clothesid, t2.clothesid)
from (select t.*
from t
where t.userid = 1
) t1 full join
(select t.*
from t
where t.userid = 2
) t2
on t1.clothesid = t2.clothesid
where t1.clothesid is null or t2.clothesid is null;
Actually, I think I have a simpler solution:
select (case when min(t.userid) = 1 then 2 else 1 end), clothesid
from t
group by clothesid
having count(*) = 1;
Here is a db<>fiddle.
Left join all the combinations of userid and clothesid to the table and return only the unmatched rows:
select t1.userid, t2.clothesid
from (select distinct userid from tablename) t1
cross join (select distinct clothesid from tablename) t2
left join tablename t on t.userid = t1.userid and t.clothesid = t2.clothesid
where t.userid is null
Or with the operator EXCEPT:
select t1.userid, t2.clothesid
from (select distinct userid from tablename) t1
cross join (select distinct clothesid from tablename) t2
except
select userid, clothesid
from tablename
See the demo.
Results:
> userid | clothesid
> -----: | --------:
> 1 | 4
> 1 | 5
> 2 | 3

Selecting the MIN(date) and the MAX(date) with the MAX(date) Freight Values

I need the MIN(Orderdate) and MAX(Orderdate) with the MAX(Orderdate) Freight values.
I've tried using a CTE and I am struggling to eliminate duplicate rows for the CustomerID
USE Northwind
GO
WITH CTE AS (
SELECT a.customerID,
MAX(b.OrderDate) AS LastOrder,
MIN(b.OrderDate) AS FirstOrder
FROM Orders AS b
INNER JOIN Customers AS a
ON b.CustomerID = a.CustomerID
GROUP BY a.CustomerID
)
SELECT CTE.customerID, CTE.FirstOrder, d.OrderDate as LastOrder, d.Freight
FROM CTE
INNER JOIN Orders as d
On CTE.CustomerID = d.CustomerID
GROUP BY CTE.CustomerID, CTE.FirstOrder, d.Freight, d.OrderDate
HAVING d.OrderDate = MAX(d.OrderDate)
I am trying to get these results which should display 89 records.
CustomerID FirstOrder LastOrder Freight
| ALFKI | 1997-08-25 | 1998-04-09 | 1.21 |
| ANATR | 1996-09-18 | 1998-03-04 | 39.92 |
| ANTON | 1996-11-27 | 1998-01-28 | 58.43 |
| AROUT | 1996-11-15 | 1998-04-10 | 33.80 |
| BERGS | 1996-08-12 | 1998-03-04 | 151.52 |
Just to Keep it simple and in line with the question. The Subquery CTE already has the customerID and the LastOrder(Max Order Date). Joining the LastOrder column in CTE to the Order tables OrderDate will give the expected results.
and d.OrderDate = CTE.LastOrder
Full Query:
WITH CTE AS (
SELECT a.customerID,
MAX(b.OrderDate) AS LastOrder,
MIN(b.OrderDate) AS FirstOrder
FROM Orders AS b
INNER JOIN Customers AS a
ON b.CustomerID = a.CustomerID
GROUP BY a.CustomerID
)
SELECT CTE.customerID, CTE.FirstOrder, d.OrderDate as LastOrder, d.Freight
FROM CTE
INNER JOIN Orders as d
On CTE.CustomerID = d.CustomerID
and d.OrderDate = CTE.LastOrder
Just use conditional aggregation:
SELECT o.customerID,
MAX(o.OrderDate) AS LastOrder,
MIN(o.OrderDate) AS FirstOrder,
MAX(CASE WHEN seqnum = 1 THEN o.freight END) as lastFreight
FROM (SELECT o.*,
ROW_NUMBER() OVER (PARTITION BY o.customerID ORDER BY o.OrderDate DESC) as seqnum
FROM Orders o
) o
GROUP BY o.CustomerID;
Note that you do not appear to need the Customer table. All the information you need is in Orders (I doubt you are using Customer to remove rows.)

SQL multiple results on one row when only one column has different values

I currently have a similar query to this one..
select i.App_Id as ApplicationId,
Cast(i.ObjectId as NVARCHAR(50)) as ObjectId,
1 as ActivityId,
Cast(case
when oh.ObjectId is null then 0
else 1
end as BIT) as Highlight,
iu.UserId as UserId
from table0 i
inner join table1 iu
on i.IdeaID = iu.IdeaID
left join table2 oh
on oh.ObjectId = i.IdeaID
left join table3 mIS
on i.IdeaID = mIS.IdeaID
AND mIS.EndTime is null
inner join table4 mISF
on mISF.StateFluxId = mIS.StateFluxId
where (iu.RelationId = 1 or iu.RelationId = 2)
which is returning, for example:
2 | 1 | 1 | 1 | 1
2 | 1 | 1 | 1 | 2
2 | 1 | 1 | 1 | 3
I'm trying to change it in order to merge the results of the 5th column when the other column values are the same:
2 | 1 | 1 | 1 | 1,2,3
Is this possible? Didn't manage to accomplish it using the Stuff function..
Thanks!
Have you tried like this,
SELECT DISTINCT i.App_Id AS ApplicationId
,Cast(i.ObjectId AS NVARCHAR(50)) AS ObjectId
,1 AS ActivityId
,Cast(CASE
WHEN oh.ObjectId IS NULL
THEN 0
ELSE 1
END AS BIT) AS Highlight
,
--iu.UserId as UserId
(stuff(SELECT ',' + userid FROM table1 WHERE Ideaid = iu.IdeaId FOR XML path(''), 1, 1, '')) AS UserId
FROM table0 i
INNER JOIN table1 iu ON i.IdeaID = iu.IdeaID
LEFT JOIN table2 oh ON oh.ObjectId = i.IdeaID
LEFT JOIN table3 mIS ON i.IdeaID = mIS.IdeaID
AND mIS.EndTime IS NULL
INNER JOIN table4 mISF ON mISF.StateFluxId = mIS.StateFluxId
WHERE (
iu.RelationId = 1
OR iu.RelationId = 2
)
Based on your code I have added the XML PATH () .Please do necessary changes according to your requirement
select i.App_Id as ApplicationId,
Cast(i.ObjectId as NVARCHAR(50)) as ObjectId,
1 as ActivityId,
Cast(case
when oh.ObjectId is null then 0
else 1
end as BIT) as Highlight,
stuff(
(
SELECT ',' + CAST(IU.USERID AS VARCHAR(10))
FROM table1 t2 WHERE iu.IdeaID = t2.IdeaID
FOR XML PATH('')
)
,1,1,'') AS USERID
from table0 i
inner join table1 iu
on i.IdeaID = iu.IdeaID
left join table2 oh
on oh.ObjectId = i.IdeaID
left join table3 mIS
on i.IdeaID = mIS.IdeaID
AND mIS.EndTime is null
inner join table4 mISF
on mISF.StateFluxId = mIS.StateFluxId
where (iu.RelationId = 1 or iu.RelationId = 2)
GROUP BY i.App_Id
,i.ObjectId,
oh.ObjectId

Why my query with union operator returns only fields from first select?

I need to get all values from table and values with condition for 'not null'.
So I make two SELECT statements.
select oa.dept_id, COUNT(oa.id) quantity, sum(oa.premium) 'sum'
from Table1 oa
Left Join Table2 od On od.id = oa.dept_id
group by oa.dept_id
Union all
select oa1.dept_id, COUNT(oa1.id) quantity1, sum(oa1.premium) 'sum1'
from Table1 oa1
Left Join Table2 od1 On od1.id = oa1.dept_id
where oa1.action is not null
group by oa1.dept_id
I expect result like this with 70 rows:
-----------------------------------------------
| dept.id | quantity | sum | quantity1 | sum1 |
-----------------------------------------------
I got result like this with 130 rows:
----------------------------
| dept.id | quantity | sum |
----------------------------
You need to use join
select a.dept_id, quantity, sum,quantity1,sum1
from
(
select oa.dept_id, COUNT(oa.id) quantity, sum(oa.premium) 'sum'
from Table1 oa
Left Join Table2 od On od.id = oa.dept_id
group by oa.dept_id
) a
join
(
select oa1.dept_id, COUNT(oa1.id) quantity1, sum(oa1.premium) 'sum1'
from Table1 oa1
Left Join Table2 od1 On od1.id = oa1.dept_id
where oa1.action is not null
group by oa1.dept_id
) b
on a.dept_id=b.dept_id

Count Customers based on item master

I need you to help me on writing two queries in SQL Server 2008 that shows the following information based on item master:
Brand wise count on customer master plus customer who purchased the brand
Item Wise count of customer master plus customer who purchased the item
Here the link that shows the table information and the query which I tried.
Click here to view the table in SQL Fiddle
SELECT
brandname,
division,
route,
DivisionTotalCustomersCount = MAX(DivisionTotalCustomersCount),
RouteTotalCustomersCount = MAX(RouteTotalCustomersCount),
PurchasedCustomersCount = SUM(PurchasedCustomersCount)
FROM
(SELECT
i.brandname,
c.division,
c.route,
DivisionTotalCustomersCount =
(SELECT COUNT(distinct x.CustomerID)
FROM CustomerMaster x
WHERE x.division = c.division),
RouteTotalCustomersCount =
(SELECT COUNT(distinct x.CustomerID)
FROM CustomerMaster x
WHERE x.Route = c.route),
PurchasedCustomersCount = count(distinct C.CustomerID)
FROM CustomerMaster c
LEFT OUTER JOIN SalesData s on c.CustomerID = s.CustomerID
right outer join ItemMaster i on s.item = i.itemcode
GROUP BY i.brandname, c.division, c.route) A
GROUP BY
brandname, division, route
ORDER BY 1
Result Should as below
Excelsheet
I think you need to go reconsider the report and maybe splitting it out into multiple reports.
It does not make sense to have a route count as well as a divisional count if they are counting things at different levels of aggregation. So have a route count and division count report.
Either way, division and route is going to be null for 100PLUS because there are no customers for that brand which means there is no route or division info available.
--Division Count
SELECT BrandName, Division, COUNT(CustomerMaster.CustomerID) [Customer Count]
FROM ItemMaster LEFT OUTER JOIN
SalesData ON ItemMaster.BrandName = SalesData.Brand LEFT OUTER JOIN
CustomerMaster ON SalesData.CustomerID = CustomerMaster.CustomerID
GROUP BY BrandName, Division
--Route Count
SELECT BrandName, Route, Division, COUNT(CustomerMaster.CustomerID) [Customer Count]
FROM ItemMaster LEFT OUTER JOIN
SalesData ON ItemMaster.BrandName = SalesData.Brand LEFT OUTER JOIN
CustomerMaster ON SalesData.CustomerID = CustomerMaster.CustomerID
GROUP BY BrandName, Route, Division
Using your sqlfiddle data there are 25 sales records & 18 distinct brand/ division/ route/ customer records and there are no sales invloving 100PLUS
select
B.BrandName
, V.Division
, coalesce(Brand_count,0) as Brand_count
, coalesce(Division_count,0) as Division_count
from (select distinct BrandName from ItemMaster) as B
cross join (select distinct Division from CustomerMaster) as V
left join (
select
Brand
, Division
, sum(cust_count) over (partition by Brand) as Brand_count
, sum(cust_count) over (partition by Division) as Division_count
from (
select
S.Brand
, C.Division
, count(distinct S.CustomerID) cust_count
from salesdata as S
inner join CustomerMaster as C
on S.CustomerID = C.CustomerID
inner join ItemMaster as I
on S.item = I.ItemCode
group by
S.Brand
, C.Division
) as S
) as D
on B.BrandName = D.Brand
and V.Division = D.Division
order by
B.BrandName
, V.Division
;
| BRANDNAME | DIVISION | BRAND_COUNT | DIVISION_COUNT |
|-----------|----------|-------------|----------------|
| 100PLUS | Dubai | 0 | 0 |
| 100PLUS | RAK | 0 | 0 |
| KITCO | Dubai | 9 | 11 |
| KITCO | RAK | 9 | 7 |
| Red Bull | Dubai | 9 | 11 |
| Red Bull | RAK | 9 | 7 |
http://sqlfiddle.com/#!3/fecb0/27
All Credit to #kevriley
select
A.BrandName,
B.Division,
B.Route,
B.DivisionTotalCustomers,
B.RouteTotalCustomers,
isnull(C.PurchasedCustomersCount,0) as PurchasedCustomersCount
from
(
select distinct
BrandName, Route, Division
from dbo.ItemMaster
cross join dbo.CustomerMaster
) A
join
(
select distinct
Division,
Route,
DENSE_RANK() over (partition by Division order by c.CustomerID asc) + DENSE_RANK() over (partition by Division order by c.CustomerID desc) - 1 as DivisionTotalCustomers ,
DENSE_RANK() over (partition by ROUTE order by c.CustomerID asc) + DENSE_RANK() over (partition by ROUTE order by c.CustomerID desc) - 1 as RouteTotalCustomers
from CustomerMaster c
left join SalesData s on c.CustomerID = s.CustomerID
) B on B.Division = A.Division and B.Route = A.Route
left join
(
select
s.brand,
c.division,
c.route,
PurchasedCustomersCount = count(distinct C.CustomerID)
FROM CustomerMaster c
JOIN SalesData s on c.CustomerID = s.CustomerID
--join ItemMaster i on s.item = i.itemcode
GROUP by s.brand, c.division, c.route
) C on A.Brandname = C.Brand and C.Division = A.Division and C.Route = A.Route
See the same on SQL Fiddle
Select B.Brandname,B.Division,C AS DivisionTotalCustomerCount,
ISNULL(T.Count,0) AS PURCHASEDCUSTOMERSCOUNT
from
(
Select CM.Division,M.BrandName,COUNT(distinct CM.CustomerID) AS C
from dbo.CustomerMaster CM
CROSS JOIN ItemMaster M
GROUP BY CM.Division,M.BrandName
)B
LEFT JOIN
(Select Division,Brand,COUNT(Distinct C.CustomerID) As Count from CustomerMaster C
JOIN salesdata D
On C.CustomerID=D.CustomerID
where D.Brand='Red Bull'
GROUP BY Division,Brand
)T
ON B.Brandname=T.Brand
and B.Division=T.Division
Order by 1,2