I have the following table
+---------+----------+--------+------------+------------+
| Country | Provider | Status | End Date | Start Date |
+---------+----------+--------+------------+------------+
| US | P1 | 1 | 1/1/2018 | 2/2/2016 |
| US | P2 | 1 | 11/12/2017 | 3/11/2016 |
| US | P3 | 1 | 10/11/2016 | 4/5/2016 |
| US | P4 | 1 | 5/12/2016 | 9/1/2015 |
| China | P1 | 2 | NA | 2/2/2016 |
| China | P2 | 2 | 11/19/2018 | 3/11/2016 |
| China | P3 | 3 | 6/8/2018 | 4/5/2016 |
| China | P4 | 1 | 9/6/2017 | 9/1/2015 |
+---------+----------+--------+------------+------------+
Expected Result
+---------+------+------+------+------+-----------+-----------+-----------+-----------+---------------+---------------+---------------+---------------+-------------+-------------+-------------+-------------+
| Country | P1 | P2 | P3 | P4 | P1 Status | P2 Status | P3 Status | P4 Status | P1 Start Date | P2 Start Date | P3 Start Date | P4 Start Date | P1 End Date | P2 End Date | P3 End Date | P14End Date |
+---------+------+------+------+------+-----------+-----------+-----------+-----------+---------------+---------------+---------------+---------------+-------------+-------------+-------------+-------------+
| US | NULL | NULL | NULL | NULL | 1 | 1 | 1 | 1 | 2/2/2016 | 3/11/2016 | 4/5/2016 | 9/1/2015 | 1/1/2018 | 11/12/2017 | 10/11/2016 | 5/12/2016 |
| China | NULL | NULL | NULL | NULL | 1 | 2 | 3 | 1 | 2/2/2016 | 3/11/2016 | 4/5/2016 | 9/1/2015 | NA | 11/19/2018 | 6/8/2018 | 9/6/2017 |
+---------+------+------+------+------+-----------+-----------+-----------+-----------+---------------+---------------+---------------+---------------+-------------+-------------+-------------+-------------+
can you guys help me pivot this table to get expected output?
P.S. - Don't worry about the NULL columns (P1, P2, P3 and P4), i can just create them in SELECT statement dynamically.
I have used the MAX function combined with either a CASE or IIF to achieve similar results in the past. Essentially, you have to manually pivot the table. The CASE or IIF is used to only return a value based on the secondary selector (Provider in your case). Then the MAX gets rid of the NULL values created for the other Providers.
Here is an short snippet to get you started. You should be able to expand it out to build up the table you are expecting.
SELECT
Country,
P1Status = MAX(IIF(Provider = 'P1', Status, NULL)),
P2Status = MAX(IIF(Provider = 'P2', Status, NULL)),
P1StartDate = MAX((IIF(Provider = 'P1', StartDate, NULL)),
P2StartDate = MAX((IIF(Provider = 'P1', StartDate, NULL))
FROM
Table
GROUP BY
Country
Related
I have the following tables
User
+--------+------+
| UserID | Name |
+--------+------+
| User1 | John |
| User2 | Mike |
+--------+------+
Device
+----------+------------+------------+------+
| DeviceID | DeviceName | DeviceType | Good |
+----------+------------+------------+------+
| 1 | Device1 | A | 0 |
| 2 | Device2 | A | 1 |
| 3 | Device7 | B | 0 |
| 4 | Device8 | B | 1 |
| 5 | Device11 | C | 0 |
| 6 | Device12 | C | 1 |
+----------+------------+------------+------+
UserDevice
+--------------+--------+----------+
| UserDeviceID | UserID | DeviceID |
+--------------+--------+----------+
| z | User1 | 1 |
| y | User1 | 3 |
| x | User1 | 5 |
| w | User2 | 2 |
| v | User2 | 4 |
| u | User2 | 6 |
+--------------+--------+----------+
I want to join these tables like below
+----------+-------------+-------------+-------------+
| UserName | DeviceTypeA | DeviceTypeB | DeviceTypeC |
+----------+-------------+-------------+-------------+
| User1 | Device1 | Device7 | Device11 |
| User2 | Device2 | Device8 | Device22 |
+----------+-------------+-------------+-------------+
I tried all types of join query but unfortunately, I could not get the data in the above format. Could someone please help?
You can do this using PIVOT (documentation)
SELECT P.[Name], P.A AS DeviceTypeA, P.B AS DeviceTypeB, P.C AS DeviceTypeC
FROM
(
SELECT U.[Name], D.DeviceName, D.DeviceType
FROM [User] U
INNER JOIN DeviceUser DU
ON DU.UserID = U.UserID
INNER JOIN Device D
ON D.DeviceID = DU.DeviceID
) AS X
PIVOT
(
MAX(X.DeviceName)
FOR X.DeviceType IN([A], [B], [C])
) AS P;
Note however that this will return only one device name for a certain user and device type even if there are more devices of a device type for a that user.
i have a SQL that displays turnover, stock and other values for stores grouped by month. Logically, if there is no value for a month, the month doesn't appear. The target is that the empty month should appear and display "NULL" for the values. The empty months should range from the #FROM to the #TO parameter (201807 to 201907) in this case.
Before:
+-------+--------+----------+----------+-------+
| Store | Month | Incoming | Turnover | Stock |
+-------+--------+----------+----------+-------+
| 123 | 201810 | 5 | 4 | 1 |
| 123 | 201811 | 0 | 1 | 0 |
| 123 | 201901 | 25 | 5 | 20 |
| 123 | 201902 | 5 | 10 | 15 |
| 123 | 201903 | 8 | 9 | 14 |
| 123 | 201904 | 5 | 4 | 15 |
| 123 | 201905 | 10 | 5 | 20 |
+-------+--------+----------+----------+-------+
After:
+-------+--------+----------+----------+-------+
| Store | Month | Incoming | Turnover | Stock |
+-------+--------+----------+----------+-------+
| 123 | 201807 | NULL | NULL | NULL |
| 123 | 201808 | NULL | NULL | NULL |
| 123 | 201809 | NULL | NULL | NULL |
| 123 | 201810 | 5 | 4 | 1 |
| 123 | 201811 | 0 | 1 | 0 |
| 123 | 201812 | NULL | NULL | NULL |
| 123 | 201901 | 25 | 5 | 20 |
| 123 | 201902 | 5 | 10 | 15 |
| 123 | 201903 | 8 | 9 | 14 |
| 123 | 201904 | 5 | 4 | 15 |
| 123 | 201905 | 10 | 5 | 20 |
| 123 | 201906 | NULL | NULL | NULL |
| 123 | 201907 | NULL | NULL | NULL |
+-------+--------+----------+----------+-------+
Code Example: db<>fiddle
I have absolutely no idea how to solve this and will thank you in advance for your help! :)
You can try to use cte recursive make a calendar table, then do outer-join
;WITH CTE AS (
SELECT CAST(CAST(#FROM AS VARCHAR(10)) + '01' AS DATE) fromDt,
CAST(CAST(#TO AS VARCHAR(10)) + '01' AS DATE) toDt,
Store
FROM (SELECT DISTINCT Store FROM #Test) t1
UNION ALL
SELECT DATEADD(MONTH,1,fromDt),toDt,Store
FROM CTE
WHERE DATEADD(MONTH,1,fromDt) <= toDt
)
SELECT FORMAT(fromDt,'yyyyMM') Month,
c.Store,
t.Incoming,
t.Turnover,
t.Stock
FROM CTE c
LEFT JOIN #Test t on
c.fromDt = CAST(CAST(t.Month AS VARCHAR(10)) + '01' AS DATE)
and
c.Store = t.Store
sqlfiddle
I need to sort a table and I need to display the rows that include Nulls at the bottom. Whenever I run the below query
select * from t1
order by status, date;
Nulls show up in the first row which I don't want:
+--------+------------+--+
| Status | Date | |
+--------+------------+--+
| 1 | NULL | |
| 1 | 2011-12-01 | |
| 1 | 2011-12-21 | |
| 2 | NULL | |
| 2 | 2005-09-02 | |
| 3 | 2000-08-07 | |
| | | |
+--------+------------+--+
This is what I need:
+--------+------------+--+
| Status | Date | |
+--------+------------+--+
| 1 | 2011-12-01 | |
| 1 | 2011-12-21 | |
| 1 | NULL | |
| 2 | 2005-09-02 | |
| 2 | NULL | |
| 3 | 2000-08-07 | |
| | | |
+--------+------------+--+
How can I do it?
select * from t1
order by status,
date,
CASE WHEN date is NULL
THEN 1
ELSE 0
END;
Would this work: order by col asc nulls last?
I made a INNER JOIN in stored procedure, but I don't know what to put to my WHERE clause to filter those column with null values and only shows those rows who has not null on a particular column.
CREATE PROCEDURE [dbo].[25]
#param1 int
AS
SELECT c.Name, c.Age, c2.Name, c2.Country
FROM Cus C
INNER JOIN Cus2 C2 ON c.id = c2.id
WHERE c2.country is not null and c2.id = #param1
Order by c2.Country
RETURN 0
ID 1
+-----+----+---------+---------+
| QID | ID | Name | Country |
+-----+----+---------+---------+
| 1 | 1 | Null | PH |
| 2 | 1 | Null | CN |
| 3 | 1 | Japhet | USA |
| 4 | 1 | Abegail | UK |
| 5 | 1 | Norlee | Ger |
+-----+----+---------+---------+
ID 2
+-----+----+----------+---------+
| QID | ID | Name | Country |
+-----+----+----------+---------+
| 1 | 2 | Null | PH |
| 2 | 2 | Null | CN |
| 3 | 2 | Reynaldo | USA |
| 4 | 2 | Abegail | UK |
| 5 | 2 | Norlee | Ger |
+-----+----+----------+---------+
ID 3
+-----+----+----------+---------+
| QID | ID | Name | Country |
+-----+----+----------+---------+
| 1 | 3 | Gab | PH |
| 2 | 3 | Null | CN |
| 3 | 3 | Reynaldo | USA |
| 4 | 3 | Abegail | UK |
| 5 | 3 | Norlee | Ger |
+-----+----+----------+---------+
I want when I choose any of the user in the C Table it will display the C child table data and remove the null name rows and remain the rows with not null name column.
Desired Result:
C Table (Parent)
+----+---------+-----+
| ID | Name | Age |
+----+---------+-----+
| 3 | Abegail | 31 |
+----+---------+-----+
C2 Table (Child)
+-----+----+----------+---------+
| QID | ID | Name | Country |
+-----+----+----------+---------+
| 1 | 3 | Gab | PH |
| 3 | 3 | Reynaldo | USA |
| 4 | 3 | Abegail | UK |
| 5 | 3 | Norlee | Ger |
+-----+----+----------+---------+
WHERE column IS NOT NULL is the syntax to filter out NULL values.
Solution 1: test not null value
Example:
WHERE yourcolumn IS NOT NULL
Solution 2: test comparaison value in your where clause (comparaison substract null values)
Examples:
WHERE yourcolumn = value
WHERE yourcolumn <> value
WHERE yourcolumn in ( value)
WHERE yourcolumn not in ( value)
WHERE yourcolumn between value1 and value2
WHERE yourcolumn not between value1 and value2
I'm trying to have 2 tables (In this case it's actually 1 table in a self join) joined by their matching children.
Let me preface the purpose of this which might give a better understanding what I need:
I'm trying to look up a new order that I just got, to see if we ever had the same order, in order to find out in which box type this would be packaged.
So i'd need the matching order to contain the same item and the same qty for the item.
Look at the tables below and note that order 1300981 has the same items as order 1303097, how do I write this join?
Remember: I don't want the results to include any matches that do not match %100.
SQL Fiddle
OrderMain:
| OrderID | BoxId |
|---------|--------|
| 1300981 | 34 |
| 1303096 | (null) |
| 1303097 | (null) |
| 1303098 | (null) |
| 1303099 | (null) |
| 1303100 | (null) |
| 1303101 | (null) |
| 1303102 | (null) |
| 1303103 | (null) |
| 1303104 | B1 |
| 1303105 | (null) |
| 1303106 | (null) |
| 1303107 | 48 |
| 1303108 | (null) |
| 1303109 | (null) |
| 1303110 | (null) |
| 1303111 | (null) |
| 1303112 | (null) |
| 1303113 | (null) |
| 1303114 | (null) |
| 1303115 | (null) |
| 1303116 | (null) |
| 1303117 | (null) |
Order Detail:
| id | OrderID | Item | Qty |
|----|---------|--------|-----|
| 1 | 1300981 | 172263 | 3 |
| 2 | 1300981 | 171345 | 3 |
| 3 | 1300981 | 138757 | 3 |
| 4 | 1303117 | 231711 | 1 |
| 5 | 1303116 | 227835 | 1 |
| 6 | 1303115 | 244798 | 1 |
| 7 | 1303114 | 121755 | 1 |
| 8 | 1303113 | 145275 | 2 |
| 9 | 1303112 | 219554 | 1 |
| 10 | 1303111 | 179385 | 1 |
| 11 | 1303110 | 6229 | 1 |
| 12 | 1303109 | 217330 | 1 |
| 13 | 1303108 | 243596 | 1 |
| 14 | 1303107 | 246758 | 1 |
| 15 | 1303106 | 193931 | 1 |
| 16 | 1303105 | 244659 | 1 |
| 17 | 1303104 | 192548 | 1 |
| 18 | 1303103 | 228410 | 1 |
| 19 | 1303102 | 147474 | 1 |
| 20 | 1303101 | 239191 | 1 |
| 21 | 1303100 | 243594 | 1 |
| 22 | 1303099 | 232301 | 1 |
| 23 | 1303098 | 201212 | 1 |
| 24 | 1303097 | 172263 | 3 |
| 25 | 1303097 | 171345 | 3 |
| 26 | 1303097 | 138757 | 3 |
| 27 | 1303096 | 172263 | 3 |
| 28 | 1303096 | 171345 | 1 |
| 29 | 1303096 | 138757 | 3 |
| 30 | 1303095 | 172263 | 3 |
Expected Results
| OrderID | BoxId |
|---------|--------|
| 1303097 | 34 |
May be a weird way to do this, but if you convert the order details to xml and compare it to other orders, you can look for matches.
WITH BoxOrders AS
(
SELECT om.[OrderId],
om.[BoxId],
(SELECT Item, Qty
FROM orderDetails od
WHERE od.[OrderId] = om.[OrderId]
ORDER BY Item
FOR XML PATH('')) Details
FROM orderMain om
WHERE BoxID IS NOT NULL
)
SELECT mo.OrderId, bo.BoxId
FROM BoxOrders bo
JOIN (
SELECT om.[OrderId],
om.[BoxId],
(SELECT Item, Qty
FROM orderDetails od
WHERE od.[OrderId] = om.[OrderId]
ORDER BY Item
FOR XML PATH('')) Details
FROM orderMain om
WHERE BoxID IS NULL
) mo ON bo.Details = mo.Details
SQL Fiddle
Here's a different approach using SQL and a few analytics.
This joins order detail to itself based on item and qty and order number < other order number and ensures the count of items in each order matches. Thus if items match, count matches and qty matches then the order has the same items.
This returns both orders but easily enough to adjust. Using the CTE so the count materializes. Pretty sure you can't use a having with an analytic like this.
The one major assumption I'm making is that order numbers are sequential and when you say see if an older order exists, I should only need to look at earlier order numbers when evaluating if a prior order had the same items and quantities.
I'm also assuming a 100% match means: Exact same items. Same Quantity of items. and SAME Item Count so count of items for order 1 is 3 and order 2 is 3 and items and quantities match that is 100% but if order 2 had 4 items and order 1 only had 3, no match.
with cte as (
SELECT distinct OD1.OrderID PriorOrder, od2.orderID newOrder, OM.BoxId,
count(OD1.Item) over (partition by OD1.OrderID) OD1Cnt,
count(OD2.Item) over (partition by OD2.OrderID) OD2cnt
FROM OrderDetails OD1
INNER JOIN orderDetails OD2
on OD1.item=OD2.item
and od1.qty = od2.qty
and OD1.OrderID < OD2.OrderID
LEFT JOIN ORderMain OM
on OM.OrderID = OD1.orderID)
Select PriorOrder, NewOrder, boxID from cte where od1cnt = od2cnt