How can I retrieve this schema by SQL query? - sql

This is my table and its data :
-------------------------------------
rid mid qty price tname
-------------------------------------
10 A 1000 400 Buy
11 A 2000 420 Buy
12 B 1700 600 Buy
13 A 600 450 Sell
And I want to have such output :
----------------------------------------------------------------
mid SUM_Buy tname SUM_Sell tname SUM_Buy_minus_SUM_Sell
----------------------------------------------------------------
A 3000 Buy 600 Sell 2400
B 1700 Buy NULL NULL NULL

Thank you for updating your question with consumable data. An even better approach is posting ddl and sample data so people can just grab it and roll. I did that for you.
declare #something table
(
rid int
, mid char(1)
, qty int
, price int
, tname varchar(10)
)
insert #something values
(10, 'A', 1000, 400, 'Buy')
, (11, 'A', 2000, 420, 'Buy')
, (12, 'B', 1700, 600, 'Buy')
, (13, 'A', 600 , 450, 'Sell')
In that type of format it is super easy for others to help.
You can solve this using conditional aggregation. I used tname1 and tname2 because outside of SSMS you don't want multiple columns to have the same name. But those are probably just noise and not really needed as they provide no benefit to the results.
select s.mid
, Sum_Buy = sum(case when tname = 'Buy' then qty end)
, tname1 = 'Buy'
, Sum_Sell = sum(case when tname = 'Sell' then qty end)
, tname2 = 'Sell'
, SUM_Buy_minus_SUM_Sell = sum(case when tname = 'Buy' then qty end) - sum(case when tname = 'Sell' then qty end)
from #something s
group by s.mid
order by s.mid

You might try this ( use grouping by mid column with aggregations by contribution of case..when statements ) :
with t(rid,mid,qty,price,tname) as
(
select 10,'A',1000,400,'Buy' union all
select 11,'A',2000,420,'Buy' union all
select 12,'B',1700,600,'Buy' union all
select 13,'A',600,450,'Sell'
)
select t.mid, sum(case when tname='Buy' then qty else 0 end) as SUM_Buy,
min(case when tname='Buy' then tname else null end) as tname,
sum(case when tname='Sell' then qty else null end) as SUM_Sell,
max(case when tname='Sell' then tname else null end) as tname,
(sum(case when tname='Buy' then qty else 0 end) -
sum(case when tname='Sell' then qty else null end)) as
SUM_Buy_minus_SUM_Sell
from t
group by t.mid

Related

pivot multi column and mutil row

this is my origin data:
ID New LikeNew Old Warehouse
1 10 100 20 LA
1 12 130 40 CA
2 90 200 10 LA
2 103 230 30 CA
i want to get the following format:
ID LA_new LA_likeNew LA_Old CA_New CA_LikeNew CA_Old
1 10 100 20 12 130 40
2 90 200 10 103 230 30
I can only pivot on each column but can not do on all 3 columns(New, LikeNew, Old) , so how can I do that?
You can accomplish this by using conditional logic to create your fields and grouping:
select id,
max(case when warehouse = 'LA' then new else null end) LA_New,
max(case when warehouse = 'LA' then likenew else null end) LA_likeNew,
max(case when warehouse = 'LA' then old else null end) LA_Old,
max(case when warehouse = 'CA' then new else null end) CA_New,
max(case when warehouse = 'CA' then likenew else null end) CA_likeNew,
max(case when warehouse = 'CA' then old else null end) CA_Old
from yourtable
group by id
Alternatively, you can use WITH Common Table Expression
DECLARE #T AS TABLE
(
id INT ,
New INT ,
likeNew INT ,
old INT ,
Warehouse VARCHAR(50)
)
INSERT INTO #T
( id, New, likeNew, old, Warehouse )
VALUES ( 1, 10, 100, 20, 'LA' ),
( 1, 12, 130, 40, 'CA' ),
( 2, 90, 200, 10, 'LA' ),
( 2, 103, 230, 30, 'CA' );
WITH cte
AS ( SELECT *
FROM #T
WHERE Warehouse = 'LA'
),
cte1
AS ( SELECT *
FROM #T
WHERE Warehouse = 'CA'
)
SELECT a.id ,
a.new [LA_New] ,
a.likeNew [LA_LikeNew] ,
a.Old [LA_Old] ,
b.new [CA_New] ,
b.likeNew [CA_LikeNew] ,
b.Old [CA_Old]
FROM cte A
JOIN cte1 B ON a.id = b.id
Result:
id LA_New LA_LikeNew LA_Old CA_New CA_LikeNew CA_Old
----------- ----------- ----------- ----------- ----------- ----------- -----------
1 10 100 20 12 130 40
2 90 200 10 103 230 30

Mutually exclusive counts in SQL

The table that I need to query looks like this
ID - Account - Product
1 - 002 - Bike
2 - 003 - Bike
4 - 003 - Motor
5 - 004 - Car
I need to be able to retrieve the number of accounts that purchased the each of the products and combinations of the products, like this
Bike | Car | Motor | Bike&Car | Bike&Motor | Car&Motor | Bike&Car&Motor
Note that an account that purchased a combination of products will be counted as 1.
Please help me in retrieving this data.
You can do this using two levels of aggregation. One method puts the values on different rows:
select has_bike, has_motor, has_car, count(*)
from (select account,
max(case when product = 'bike' then 1 else 0 end) as has_bike,
max(case when product = 'motor' then 1 else 0 end) as has_motor,
max(case when product = 'car' then 1 else 0 end) as has_car
from t
group by account
) t
group by has_bike, has_motor, has_car;
Or in columns:
select sum(has_bike * (1 - has_motor) * (1 - has_car)) as has_only_bike,
sum((1 - has_bike) * has_motor * (1 - has_car)) as has_only_motor,
sum((1 - has_bike) * (1 - has_motor) * has_car) as has_only_car,
. . .
from (select account,
max(case when product = 'bike' then 1 else 0 end) as has_bike,
max(case when product = 'motor' then 1 else 0 end) as has_motor,
max(case when product = 'car' then 1 else 0 end) as has_car
from t
group by account
) t;
If you only have a limited set of Products, then you can use this:
-- Create sample data
CREATE TABLE #tbl(
ID INT,
Account VARCHAR(10),
Product VARCHAR(10)
);
INSERT INTO #tbl VALUES
(1, '002', 'Bike'),
(2, '003', 'Bike'),
(3, '003', 'Motor'),
(4, '004', 'Car');
WITH Cte AS(
SELECT t1.Account, a.Products
FROM #tbl t1
CROSS APPLY (
SELECT STUFF((
SELECT '&' + t2.Product
FROM #tbl t2
WHERE t2.Account = t1.Account
ORDER BY t2.Product
FOR XML PATH(''), type).value('.[1]','nvarchar(max)'),
1, 1, '') AS Products
) a
GROUP BY t1.Account, a.Products
)
SELECT
Bike = SUM(CASE WHEN Products = 'Bike' THEN 1 ELSE 0 END),
Car = SUM(CASE WHEN Products = 'Car' THEN 1 ELSE 0 END),
Motor = SUM(CASE WHEN Products = 'Motor' THEN 1 ELSE 0 END),
[Bike&Car] = SUM(CASE WHEN Products = 'Bike&Car' THEN 1 ELSE 0 END),
[Bike&Motor] = SUM(CASE WHEN Products = 'Bike&Motor' THEN 1 ELSE 0 END),
[Car&Motor] = SUM(CASE WHEN Products = 'Car&Motor' THEN 1 ELSE 0 END),
[Bike&Car&Motor] = SUM(CASE WHEN Products = 'Bike&Car&Motor' THEN 1 ELSE 0 END)
FROM Cte;
DROP TABLE #tbl; -- Remove sample data
The idea is to generate 1 row for each Account, together with a comma-delimited Products. If you execute the query inside the CTE, you will get:
Account Products
---------- ---------------
002 Bike
003 Bike&Motor
004 Car
With that, you can do a conditional aggregation. The above uses a static solution, if you do not know the number of Products, you may need to come up with a dynamic approach.
ONLINE DEMO

SQL query for combining data from the same table

I have this table :
create table mytable
(ID varchar(10), VNDCOD INT, MANUF varchar(10), PRICE INT, COST INT);
insert into mytable values
('4', 1000, 'AG', 5455, 9384),
('4', 1000, 'A1', 16, 31),
('4', 2000, 'AG', 5253, 8339)
I want to be able to select something like this:
ID MANUF PRICE COST PRICE COST
4 AG 5455 9384 5253 8339
4 A1 16 31
If there is two MANUF for an ID, we should combine them on one line where the PRICE and COST of the one with VNDCOD 1000 is on the left and VNDCOD 2000 on the right like in my expected result. I don't know if it is possible to do this in one query. Any help would be greatly appreciated.
Either use a self-join or a MAX(CASE) (fiddle):
select t1.ID, t1.MANUF, t1.PRICE, t1.COST, t2.PRICE, t2.COST
from mytable as t1 left join mytable as t2
on t1.ID = t2.ID
and t1.MANUF = t2.MANUF
and t2.VNDCOD = 2000
where t1.VNDCOD = 1000
;
select ID, MANUF,
max(case when VNDCOD = 1000 then PRICE end),
max(case when VNDCOD = 1000 then COST end),
max(case when VNDCOD = 2000 then PRICE end),
max(case when VNDCOD = 2000 then COST end)
from mytable
group by ID, MANUF
You can readily do this with conditional aggregation:
select id,
max(case when vndcode = 1000 then price end) as price_1000,
max(case when vndcode = 1000 then cost end) as cost_1000,
max(case when vndcode = 2000 then price end) as price_2000,
max(case when vndcode = 2000 then cost end) as cost_2000
from mytable t
group by id;

SQL Inner join not working to get change from previous date

I have a table with the following data :
TradeDate Stock BuySell DayClose
--------------------------------------
10-Dec-12 ABC 1 11
10-Dec-12 ABC 2 12
11-Dec-12 ABC 1 11.5
11-Dec-12 ABC 2 12.5
11-Dec-12 DEF 1 15
11-Dec-12 DEF 2 16
and I want to query on it for a particular date 11-Dec-2012 to get the following output :
Stock Buy Sell Mid Change
--------------------------------------
ABC 11.5 12.5 12.0 0.5
DEF 15 16 15.5
Since DEF does not have data for the previous date, change should be blank for it.
I have created the following query :
Select Stock,
AVG(CASE BuySell WHEN 1 THEN DayClose END) AS 'Buy',
AVG(CASE BuySell WHEN 2 THEN DayClose END) As 'Sell',
Sum(DayClose/2) as 'Mid',
Sum(Change/2) AS Change
FROM (
select t1.Stock, t1.BuySell, t1.DayClose, Sum(t1.DayClose - t2.DayClose) as Change
FROM #myTable as t1 inner join #myTable as t2 on
t1.Stock = t2.Stock
where
t1.TradeDate = '2012-12-11' AND
t2.TradeDate = (SELECT TOP 1 TradeDate FROM #myTable WHERE TradeDate < '2012-12-11' ORDER BY TradeDate DESC)
GROUP BY
t1.Stock, t1.buysell, t1.dayclose ) AS P1 GROUP BY stock
I created a temp table #mytable for this purpose :
drop table #mytable
CREATE TABLE #myTable
(
TradeDate datetime,
stock varchar(20),
buysell int,
dayclose decimal(10,2)
)
insert into #mytable values ('10-dec-2012', 'abc' , 1, 11)
insert into #mytable values ('10-dec-2012', 'abc' , 2, 12)
insert into #mytable values ('11-dec-2012', 'abc' , 1, 11.5)
insert into #mytable values ('11-dec-2012', 'abc' , 2, 12.5)
insert into #mytable values ('11-dec-2012', 'def' , 1, 15)
insert into #mytable values ('11-dec-2012', 'def' , 2, 16)
But I am not able to get the required output, rather getting
Stock Buy Sell Mid Change
--------------------------------------------------------------
abc 11.500000 12.500000 12.00000 1.00
Can someone tell me where am I going wrong. I seem to be lost in here.
Thanks,
Monika
Please try:
;WITH T1 as(
SELECT a.TradeDate
,a.stock
,SUM(CASE WHEN a.BuySell = 1 THEN a.DayClose ELSE 0 END) Buy
,SUM(CASE WHEN a.BuySell = 2 THEN a.DayClose ELSE 0 END) Sell
,SUM(a.DayClose) / 2 AS Mid
FROM #mytable a
GROUP BY a.TradeDate, a.stock
)SELECT t.*,
t.Mid - PR.Mid AS Change
FROM T1 t
LEFT JOIN
T1 PR ON
PR.TradeDate = DATEADD(DAY, -1, t.TradeDate)
AND PR.stock = t.stock
Try this:
SELECT a.TradeDate
,a.stock
,SUM(CASE WHEN a.BuySell = 1 THEN a.DayClose ELSE 0 END) Buy
,SUM(CASE WHEN a.BuySell = 2 THEN a.DayClose ELSE 0 END) Sell
,SUM(a.DayClose) / 2 AS Mid
INTO #temp
FROM #mytable a
GROUP BY a.TradeDate, a.stock
SELECT t.*,
t.Mid - previousRecord.Mid AS Change
FROM #temp t
LEFT JOIN
#temp previousRecord ON
previousRecord.TradeDate = DATEADD(DAY, -1, t.TradeDate)
AND previousRecord.stock = t.stock
DROP TABLE #temp
All you have to do now is to select the data for a date.
Select Stock,
AVG(CASE BuySell WHEN 1 THEN DayClose END) AS 'Buy',
AVG(CASE BuySell WHEN 2 THEN DayClose END) As 'Sell',
Sum(DayClose/2) as 'Mid',
Sum(Change/2) AS Change
FROM (
select t1.Stock, t1.BuySell, t1.DayClose, Sum( t1.DayClose - t2.DayClose ) as Change
FROM #myTable as t1 left join #myTable as t2 on t2.TradeDate = (SELECT TOP 1 TradeDate FROM #myTable WHERE TradeDate < t1.TradeDate ORDER BY TradeDate DESC)
and t1.Stock = t2.Stock and t1.buysell=t2.buysell
where
t1.TradeDate = '11-12-2012'

question on Group by clause in Sql server

Table: Customer
Name Type Amount
James P 125.00
James P 125.00
James P 125.00
James R 225.00
James R 225.00
Rajiv R 155.00
Rajiv R 155.00
Rajiv R 155.00
Rajiv P 150.00
Rajiv P 150.00
Saran R 175.00
In this table structure I want a output which will give each person’s count of P, count of R, sum of Amount where type = P, Sum of amount where type = R
Any clues for me as stuck up with group by did not help me much in this scenario.
If you want the result as separate records, you simply group on the name and type:
select Name, Type, count(*) as Cnt, sum(Amount) as AmountSum
from Customer
Group by Name, Type
order by Name, Type
Result:
Name Type Cnt AmountSum
James P 3 375.00
James R 2 450.00
Rajiv P 2 300.00
Rajiv R 3 465.00
Saran R 1 175.00
If you want the count and sum for a person in the same record, you have to do some comparisons:
select
Name,
count(case Type when 'P' then 1 else null end) as CntP,
sum(case Type when 'P' then Amount else 0 end) as AmountSumP,
count(case Type when 'R' then 1 else null end) as CntR,
sum(case Type when 'R' then Amount else 0 end) as AmountSumR,
from Customer
Group by Name
order by Name
Result:
Name CntP AmountSumP CntR AmountSumR
James 3 375.00 2 450.00
Rajiv 2 300.00 3 465.00
Saran 0 0.00 1 175.00
One query, no CTE, no derived tables:
SELECT
Name,
SUM(CASE WHEN Type = 'P' THEN 1 ELSE 0 END) AS PCount,
SUM(CASE WHEN Type = 'R' THEN 1 ELSE 0 END) AS RCount,
SUM(CASE WHEN Type = 'P' THEN Amount ELSE 0 END) AS PAmount,
SUM(CASE WHEN Type = 'R' THEN Amount ELSE 0 END) AS RAmount
FROM yourTable
GROUP BY Name
using the
CREATE TABLE customer (name varchar(50), type char(1), amount decimal(6,2));
INSERT INTO customer VALUES ('James', 'P', 125.00);
INSERT INTO customer VALUES ('James', 'P', 125.00);
INSERT INTO customer VALUES ('James', 'P', 125.00);
INSERT INTO customer VALUES ('James', 'R', 225.00);
INSERT INTO customer VALUES ('James', 'R', 225.00);
INSERT INTO customer VALUES ('Rajiv', 'R', 155.00);
INSERT INTO customer VALUES ('Rajiv', 'R', 155.00);
INSERT INTO customer VALUES ('Rajiv', 'R', 155.00);
INSERT INTO customer VALUES ('Rajiv', 'P', 150.00);
INSERT INTO customer VALUES ('Rajiv', 'P', 150.00);
INSERT INTO customer VALUES ('Saran', 'R', 175.00);
SELECT
Name,
SUM(CASE WHEN Type = 'P' THEN 1 ELSE 0 END) AS PCount,
SUM(CASE WHEN Type = 'R' THEN 1 ELSE 0 END) AS RCount,
SUM(CASE WHEN Type = 'P' THEN Amount ELSE 0 END) AS PAmount,
SUM(CASE WHEN Type = 'R' THEN Amount ELSE 0 END) AS RAmount
FROM customer
GROUP BY Name
James 3 2 375.00 450.00
Rajiv 2 3 300.00 465.00
Saran 0 1 0.00 175.00
Edited Answer: After gbn pointed out a mistake in my original answer
SELECT name,
SUM( CASE WHEN [type] = 'P' THEN 1 ELSE 0 END) CountOfP ,
SUM( CASE WHEN [type] = 'R' THEN 1 ELSE 0 END) CountOfR,
SUM( CASE WHEN [type] = 'P' THEN Amount End) SumOfP ,
SUM( CASE WHEN [type] = 'R' THEN Amount END) SumOfR
FROM customer
GROUP BY name
Original Answer
SELECT name,
COUNT( CASE WHEN [type] = 'P' THEN 1 ELSE 0 END) CountOfP ,
COUNT( CASE WHEN [type] = 'R' THEN 1 ELSE 0 END) CountOfR,
SUM( CASE WHEN [type] = 'P' THEN Amount End) SumOfP ,
SUM( CASE WHEN [type] = 'R' THEN Amount END) SumOfR
FROM customer
GROUP BY name