Table Structures:
tblCustomer
Customer_id created field1 field2 cardno
--------------------------------------------------------
1014 Test1 Cell Phone 123146 1234567890
1015 Test2 Email abc#xyz.com 2345678891
tbl_TransactionDishout
Trnx_id offerNo TerminalID Created cardno
-------------------------------------------------------------------
1 1014 170924690436418 2010-05-25 12:51:59.547 1234567890
Is it possible to get the result as below date-wise records:
Enrolled Enrolled as Email Enrolled as Text Deals Redeemed
<First Date> 7 5 2 6
<Next Date> 9 3 6 14
My current query is something like this:
select created,
count(field1) Enrolled,
count(case field1 when 'E-mail' then 1 end) Enrolled_as_Email,
count(case field1 when 'Cell Phone' then 1 end) Enrolled_as_Cell
from tblCustomer c
group by created
order by created desc
But It's giving me the result of the date contained only in tblCustomer table..
Now, How to get Deals_redeemed..?
relation between tbl_transaction and tblCustomer is having same cardno...
In my understanding table tbl_TransactionDishout is an offer, and if it is followed through a record will be inserted into tblCustomers; if not, nothing will change. So deals redeemed is count of non-existing records in tblCustomers for given cardno:
select t.created,
count(c.field1) Enrolled,
count(case c.field1 when 'E-mail' then 1 end) Enrolled_as_Email,
count(case c.field1 when 'Cell Phone' then 1 end) Enrolled_as_Cell,
count(case when c.field1 is null then 1 end) [Deals Redeemed]
from tbl_TransactionDishout t left join tblCustomer c
on t.cardno = c.cardno
group by t.created
order by t.created desc
EDIT: c.created changed to t.created
Related
This is the table "tbltask",
task Ship_Operator Pick_Operator Pack_Operator
1 john kevin steve
2 kevin kevin john
3 steve john john
4 steve steve steve
5 john steve john
Now I need to get the total amount for everyone: ship, pick, pack
name ship Total pick Total pack Total
john 2 1 3
kevin 1 2 0
steve 2 2 2
I can use three statement to get the result:
select [Ship_Operator] ,count(*) as task_total from tbltask
where [Ship_Operator] in ('john','kevin','steve')
group by [Ship_Operator]
select [Pick_Operator] ,count(*) as task_total from tbltask
where [Pick_Operator] in ('john','kevin','steve')
group by [Pick_Operator]
select [Pack_Operator] ,count(*) as task_total from tbltask
where [Pack_Operator] in ('john','kevin','steve')
group by [Pack_Operator]
Is it possible to use one SQL statement?
Your help will be appreciated!
unpivot and pivot back:
with t(task,Ship_Operator,Pick_Operator,Pack_Operator) as (
select '1','john','kevin','steve' union all
select '2','kevin','kevin','john' union all
select '3','steve','john','john' union all
select '4','steve','steve','steve' union all
select '5','john','steve','john')
-------Test data set up ends here------------
select
name, Ship_Operator ship_total, Pick_Operator pick_total, Pack_Operator pack_total
from t unpivot (
name for operation in (Ship_Operator, Pick_operator, Pack_Operator)
) as x pivot (
count(task) for operation in ([Ship_Operator],[Pick_Operator],[Pack_Operator])
) as x;
Produces:
Another way is to use UNPIVOT only and then conditionally aggregate:
with t(task,Ship_Operator,Pick_Operator,Pack_Operator) as (
select '1','john','kevin','steve' union all
select '2','kevin','kevin','john' union all
select '3','steve','john','john' union all
select '4','steve','steve','steve' union all
select '5','john','steve','john')
-------Test data set up ends here------------
select
name,
count(case when operation = 'Ship_Operator' then 1 end) ship,
count(case when operation = 'Pick_Operator' then 1 end) pick,
count(case when operation = 'Pack_Operator' then 1 end) pack
from t unpivot (
name for operation in (Ship_Operator, Pick_operator, Pack_Operator)
) as x
group by name;
Produces:
Use UNION to combine all name and add a new column to just identify the different values.
Query
SELECT t.[Name],
SUM(CASE t.[Col1] WHEN 'Ship' THEN 1 ELSE 0 END) AS [Ship Total],
SUM(CASE t.[Col1] WHEN 'Pick' THEN 1 ELSE 0 END) AS [Pick Total],
SUM(CASE t.[Col1] WHEN 'Pack' THEN 1 ELSE 0 END) AS [Pack Total]
FROM(
SELECT 'Ship' AS [col1], [Ship_operator] as [Name]
FROM [tbltask]
UNION ALL
SELECT 'Pick', [Pick_operator]
FROM [tbltask]
UNION ALL
SELECT 'Pack' AS [col1], [Pack_operator]
FROM [tbltask]
)t
GROUP BY t.[Name];
And if you want the result particularly for those three names. Then add a WHERE condition in the sub-queries.
Table Structures:
tblCustomer
Customer_id created field1 field2 cardno field14
------------------------------------------------------------------------------------------------
1014 2010-05-25 12:51:59.547 Cell Phone abc#lmn.com 1234567890 Test Card
1015 2010-08-15 12:51:59.547 Email abc#xyz.com 2345678891 NULL
tbl_TransactionDishout
Trnx_id offerNo TerminalID Created VirtualCard
-------------------------------------------------------------------
1 1014 170924690436418 2010-05-25 12:51:59.547 1234567890
Relation between tbl_transaction and tblCustomer is having same cardno.
Is it possible to get the result as below date-wise records:
Enrolled Enrolled as Email Enrolled as Text Deals Redeemed
<First Date> 7 5 2 6
<Next Date> 9 3 6 14
Date should be from both tables even if it has zero records..
Enrolled - Total No of records that is summation of Enrolled as Email and Enrolled as Text.
Enrolled as Email - Where field1 = 'Email' from tblCustomer table
Enrolled as Text - Where field1 = 'cell phone' from tblCustomer table
Deals Redeemed - Where field14 <> 'Test Card' from tblCustomer table and
where DishoutResponsecode = '0000' from tbl_Transaction table
My Existing Query:
SELECT
convert(varchar, CAST(ISNULL(t1.created,t2.created) AS DATETIME), 111) created,
COUNT(CASE WHEN (t1.field1 = 'E-mail' or t1.field1 = 'Cell Phone') and (t1.field14 <> 'Test Card' or t1.field14 is null) THEN 1 END) Enrolled,
COUNT(CASE WHEN t1.field1 = 'E-mail' and (t1.field14 <> 'Test Card' and t1.field14 is null) THEN 1 END) Enrolled_as_Email,
COUNT(CASE WHEN t1.field1 = 'Cell Phone' and (t1.field14 <> 'Test Card' and t1.field14 is null) THEN 1 END) Enrolled_as_Cell,
COUNT(CASE WHEN t2.DishoutResponseCode = '0000' and (IsNull(t1.field14, '') <> 'Test Card') THEN 1 END) Deals_Redeemed
FROM tblCustomer AS t1
FULL OUTER JOIN
tbl_TransactionDishout t2
ON t1.cardno = t2.VirtualCard and t1.created = t2.created
GROUP BY
convert(varchar, CAST(ISNULL(t1.created,t2.created) AS DATETIME), 111)
ORDER BY
convert(varchar, CAST(ISNULL(t1.created,t2.created) AS DATETIME), 111) DESC
Last 4-5 records in tblCustomer table
created cardno field14
----------------------------------------------------------
2012-03-07 10:03:00.034 1234007600101240
2012-03-05 04:02:00.040 1234007600602122
2012-03-01 06:25:50.400 1234010400972168 Test Card
2012-03-01 30:05:30.022 555566669999 Test Card
2012-03-01 50:50:20.450 666677778888 Test Card
Last 4-5 records in tbl_TransactionDisout table
created VirtualCard DishoutResponseCode
-----------------------------------------------------------------------
2012-03-09 13:18:02.703 1234010400972168 0010
2012-03-09 13:17:35.307 1234010400972168 0002
2012-03-09 13:17:14.237 1234010400972168 0007
2012-03-09 13:16:57.650 1234010400972168 0002
2012-03-08 21:13:57.137 1234010400475686 0000
2012-03-08 16:50:38.273 1234010400972168 0002
2012-03-08 16:50:26.070 1234010400972168 0007
2012-03-08 16:49:49.793 1234010400972168 0002
So there is only one card in this with having response code '0000' and also not a 'Test Card'..But I am getting all the card with code = '0000' and also having 'Test Card' so that means field14 is not able to compare because it is from the different table and different date..
This is the result I get back with this query when I use the data that you specified in the main question:
SELECT
convert(varchar, CAST(ISNULL(t1.created,t2.created) AS DATETIME), 111) created,
COUNT(CASE WHEN (t1.field1 = 'Email' or t1.field1 = 'Cell Phone') and (t1.field14 <> 'Test Card' or t1.field14 is null) THEN 1 END) Enrolled,
COUNT(CASE WHEN t1.field1 = 'Email' and (IsNull(t1.field14, '') <> 'Test Card') THEN 1 END) Enrolled_as_Email,
COUNT(CASE WHEN t1.field1 = 'Cell Phone' and (IsNull(t1.field14, '') <> 'Test Card') THEN 1 END) Enrolled_as_Cell,
COUNT(CASE WHEN t2.DishoutResponseCode = '0000' and (IsNull(t1.field14, '') <> 'Test Card') THEN 1 END) Deals_Redeemed
FROM
tblCustomer AS t1
FULL OUTER JOIN
tbl_TransactionDishout t2
ON t1.cardno = t2.VirtualCard
AND t1.created = t2.created
GROUP BY
convert(varchar, CAST(ISNULL(t1.created,t2.created) AS DATETIME), 111)
ORDER BY
convert(varchar, CAST(ISNULL(t1.created,t2.created) AS DATETIME), 111) DESC
Result:
created Enrolled Enrolled_as_Email Enrolled_as_Cell Deals_Redeemed
------------------------------ ----------- ----------------- ---------------- --------------
2012/03/09 0 0 0 0
2012/03/08 0 0 0 1
2012/03/07 1 0 1 0
2012/03/05 1 0 1 0
2012/03/01 0 0 0 0
Table "tblCustomer":
Customer_id
created
field1
field2
cardno
1014
2010-05-25 12:51:59.547
Cell Phone
abc#lmn.com
1234567890
1015
2010-08-15 12:51:59.547
Email
abc#xyz.com
2345678891
Table "tbl_TransactionDishout":
Trnx_id
offerNo
TerminalID
Created
VirtualCard
1
1014
170924690436418
2010-05-25 12:51:59.547
1234567890
Expected Output:
Enrolled
Enrolled as Email
Enrolled as Text
Deals Redeemed
<First Date>
7
5
2
6
<Next Date>
9
3
6
14
I have two different queries which I need to combine into one.
First One:
SELECT CAST(FLOOR(CAST(t.created AS FLOAT )) AS Datetime) created,
COUNT(field1) Enrolled,
COUNT(CASE field1 WHEN 'E-mail' THEN 1 END) Enrolled_as_Email,
COUNT(CASE field1 WHEN 'Cell Phone' THEN 1 END) Enrolled_as_Cell
FROM tblCustomer as t
GROUP BY t.created
ORDER BY t.created DESC
Which Displays:
create
Enrolled
Enrolled_as_Email
Enrolled_as_Cell
2012-03-01 00:00:00.000
3
1
2
2012-02-29 00:00:00.000
1
0
1
Second One:
SELECT CAST(FLOOR(CAST(t.created AS FLOAT)) AS Datetime) created,
COUNT(*) [Deals_Redeemed]
FROM tbl_TransactionDishout t
LEFT JOIN tblCustomer c
ON t.VirtualCard = c.cardno
GROUP BY CAST(FLOOR(CAST(t.created AS FLOAT )) as Datetime)
ORDER BY t.created desc
Which Displays:
create
Deals_Redeemed
2012-03-02 00:00:00.000
1
2012-03-01 00:00:00.000
6
2012-02-28 00:00:00.000
1
2012-02-27 00:00:00.000
2
Now I want a record which contain date from both and should be combined into one.
But It's giving me the result of the date contained only in tblCustomer table..
How to get "Deals_redeemed"?
Note: relation between tbl_transaction and tblCustomer is having same cardno.
SELECT
CAST(t1.created AS DATE) created,
COUNT(t1.field1) Enrolled,
COUNT(CASE t1.field1 WHEN 'E-mail' THEN 1 END) Enrolled_as_Email,
COUNT(CASE t1.field1 WHEN 'Cell Phone' THEN 1 END) Enrolled_as_Cell,
COUNT(t2.created) Deals_Redeemed
FROM tblCustomer AS t1
LEFT JOIN tbl_TransactionDishout t2
ON t1.cardno = t2.VirtualCard
GROUP BY CAST(t1.created AS DATE)
ORDER BY CAST(t1.created AS DATE) DESC
Edit: Changed condition to cardno, and changed from FULL JOIN to LEFT JOIN.
You could Pivot():
select [create]
, sum([Email]+[Cell Phone]) as [Enrolled]
, max([Email]) as [Enrolled as Email]
, max([Cell Phone]) as [Enrolled as Cell Phone]
, max([Deal Redeemed]) as [Deals Redeemed]
from (
select [create]=created
, create1=created
, field1
from tblCustomer
union all
select [create]=created
, create1=created
, field1='Deal Redeemed'
from tbl_TransactionDishout
) p
pivot (
count(create1)
for field1 in ([Cell Phone],[Email],[Deal Redeemed])
) pv
group by [create]
order by [create]
I'm trying to aggregate some customer order data into one table for analysis. The data is the number of products a customer orders, then trying to determine whether the order is a small, medium, or large order, then determine the total products they bought and the cost of the order by OrderSize.
Small order - 1 - 2 products
Medium order - 3 - 4 products
Large Order - >=5 products
Here is the data:
CustomerID OrderID OrderSize OrderTotal
1 800 1 $20
2 801 1 $10
3 802 4 $85
1 803 1 $30
2 804 8 $120
3 805 1 $40
Here is the table I am attempting to build (easier to just post an image):
I could run an update query like this to populate the table:
-- Build the table --
CREATE TABLE Customers (
CustomerID varchar(10) PRIMARY KEY,
SmallOrderCount int,
SmallOrderProducts int,
SmallOrderTotal money,
MedOrderCount int,
MedOrderProducts int,
MedOrderTotal money,
LargeOrderCount int,
LargeOrderProducts int,
LargeOrderTotal money
);
-- Insert the unique customers --
INSERT INTO Customers
SELECT CustomerID FROM Orders GROUP BY CustomerID;
-- Update to populate the order information --
UPDATE Customers
SET SmallOrderCount = (SELECT count(*) FROM Orders WHERE OrderSize BETWEEN 1 AND 2 AND Orders.CustomerID = Customers.CustomerID);
UPDATE Customers
SET SmallOrderProducts = (SELECT sum(OrderSize) FROM Orders WHERE OrderSize BETWEEN 1 AND 2 AND Orders.CustomerID = Customers.CustomerID);
UPDATE Customers
SET SmallOrderTotal = (SELECT sum(OrderTotal) FROM Orders WHERE OrderSize BETWEEN 1 AND 2 AND Orders.CustomerID = Customers.CustomerID);
Then I could repeat this for the remaining 6 columns.
However, this seems like a lot of work. Is there a way to populate my Customer table using a subquery that may be less work? Or is my approach above the most direct?
You can do all of it in one INSERT command with CASE statements:
INSERT INTO Customers
SELECT CustomerID
,sum(CASE WHEN OrderSize BETWEEN 1 AND 2 THEN 1 ELSE 0 END) AS SmallOrderCount
,sum(CASE WHEN OrderSize BETWEEN 1 AND 2 THEN OrderSize ELSE 0 END) AS SmallOrderProducts
,sum(CASE WHEN OrderSize BETWEEN 1 AND 2 THEN OrderTotal ELSE 0 END) AS SmallOrderTotal
,sum(CASE WHEN OrderSize BETWEEN 3 AND 4 THEN 1 ELSE 0 END) AS MedOrderCount
,sum(CASE WHEN OrderSize BETWEEN 3 AND 4 THEN OrderSize ELSE 0 END) AS MedOrderProducts
,sum(CASE WHEN OrderSize BETWEEN 3 AND 4 THEN OrderTotal ELSE 0 END) AS MedOrderTotal
,sum(CASE WHEN OrderSize > 4 THEN 1 ELSE 0 END) AS LargeOrderCount
,sum(CASE WHEN OrderSize > 4 THEN OrderSize ELSE 0 END) AS LargeOrderProducts
,sum(CASE WHEN OrderSize > 4 THEN OrderTotal ELSE 0 END) AS LargeOrderTotal
FROM Orders
GROUP BY CustomerID;
See this working demo for the full query on data.SE.
One insert should be enough:
INSERT INTO Customers(CustomerID,SmallOrderCount,SmallOrderProducts,
SmallOrderTotal)
SELECT a.CustomerID, COUNT(a.*) as cnt, sum(a.OrderSize) as OrderSize,
sum(a.OrderTotal) as OrderTotal
FROM Orders a
WHERE a.OrderSize BETWEEN 1 AND 2
GROUP BY a.CustomerID
The query above will insert only customers whose order size is between 1 and 2. If you need to insert others as well, you can use :
INSERT INTO Customers(CustomerID,SmallOrderCount,SmallOrderProducts,
SmallOrderTotal)
SELECT a.CustomerID,
COUNT(CASE WHEN a.OrderSize BETWEEN 1 AND 2 THEN 1 END) as cnt,
sum(CASE WHEN a.OrderSize BETWEEN 1 AND 2 THEN a.OrderSize ELSE 0 END) as OrderSize,
sum(CASE WHEN a.OrderSize BETWEEN 1 AND 2 THEN a.OrderTotal ELSE 0 END ) as OrderTotal
FROM Orders a
GROUP BY a.CustomerID
I'd only create a single query (which can be used as view) for that and not a whole new persisted table.
WITH cteOrders AS (
SELECT CustomerID,
CASE WHEN OrderSize BETWEEN 1 AND 2 THEN OrderSize END SmallOrderProducts,
CASE WHEN OrderSize BETWEEN 1 AND 2 THEN OrderTotal END SmallOrderTotal,
CASE WHEN OrderSize BETWEEN 3 AND 4 THEN OrderSize END MediumOrderProducts,
CASE WHEN OrderSize BETWEEN 3 AND 4 THEN OrderTotal END MediumOrderTotal,
CASE WHEN OrderSize > 4 THEN OrderSize END LargeOrderProducts,
CASE WHEN OrderSize > 4 THEN OrderTotal END LargeOrderTotal
FROM Orders
)
SELECT CustomerID,
COUNT(SmallOrderProducts) SmallOrderCount,
COALESCE(SUM(SmallOrderProducts), 0) SmallOrderProducts,
COALESCE(SUM(SmallOrderTotal), 0) SmallOrderTotal,
COUNT(MediumOrderProducts) MediumOrderCount,
COALESCE(SUM(MediumOrderProducts), 0) MediumOrderProducts,
COALESCE(SUM(MediumOrderTotal), 0) MediumOrderTotal,
COUNT(LargeOrderProducts) LargeOrderCount,
COALESCE(SUM(LargeOrderProducts), 0) LargeOrderProducts,
COALESCE(SUM(LargeOrderTotal), 0) LargeOrderTotal
FROM cteOrders
GROUP BY CustomerID
You can do this by using single INSERT INTO SELECT statement
INSERT INTO Customers
SELECT * ,
(SELECT count(*) FROM Orders WHERE OrderSize BETWEEN 1 AND 2 AND Orders.CustomerID = CustomerID),
(SELECT sum(OrderSize) FROM Orders WHERE OrderSize BETWEEN 1 AND 2 AND Orders.CustomerID = CustomerID)
FROM CUSTOMERS
I have a table called album with the following columns:
Album_Id, User_Id, Report_Id, PhotoName
There are different Photoname on a User_Id and Report_Id combination
Like:
Album_Id User_Id Report_Id PhotoName
1 1 16 A.jpg
2 1 16 B.jpg
3 2 17 C.jpg
4 2 17 D.jpg
I just want to retrieve data in format
User_Id Report_Id PhotoName1 PhotoName2
1 16 A.jpg B.jpg
2 17 C.jpg D.jpg
Max Photos are 4...
WITH cte
AS ( SELECT * ,
ROW_NUMBER() OVER ( PARTITION BY User_Id, Report_Id ORDER BY Album_Id ) AS RN
FROM T
)
SELECT User_Id ,
Report_Id ,
MAX(CASE WHEN RN = 1 THEN PhotoName
END) AS PhotoName1 ,
MAX(CASE WHEN RN = 2 THEN PhotoName
END) AS PhotoName2 ,
MAX(CASE WHEN RN = 3 THEN PhotoName
END) AS PhotoName3 ,
MAX(CASE WHEN RN = 4 THEN PhotoName
END) AS PhotoName4
FROM cte
GROUP BY User_Id ,
Report_Id
SELECT a.User_Id, a.Report_Id, a.PhotoName as 'PhotoName1', a2.PhotoName as 'PhotoName2', a3.PhotoName as 'PhotoName3', a4.PhotoName as 'PhotoName4'
FROM album a
LEFT JOIN album a2 on a2.User_Id = a.User_Id and a2.Report_Id = a.Report_Id AND a2.Album_Id != a.Album_Id
LEFT JOIN album a3 on a3.User_Id = a.User_Id and a3.Report_Id = a.Report_Id AND a3.Album_id NOT IN (a.Album_Id, a2.Album_Id)
LEFT JOIN album a4 on a4.User_Id = a.User_Id and a4.Report_Id = a.Report_Id AND a4.Album_id NOT IN (a.Album_Id, a2.Album_Id, a3.Album_Id)
ORDER BY a.User_Id, a.Report_Id ASC;