Related
I am trying to get a count of pat_id that were either only "Sent" or only "Sent and Received"
Here is my query so far
select pat_id,
(case when addr_msg_actn_c in(1) then 'Sent' else convert(varchar(10),'Received') end) [Status]
from pat_addr_verif
where pat_id in ('Z1000354','Z1000363','Z1000392','Z1000394')
group by pat_id, addr_msg_actn_c
order by pat_id
Which generates this output
However, I'd like to simplify the output to display like this
Here's a small proof of concept. You can generate a case statement on the sum of a value to choose which text string you want.
CREATE TABLE #SentReceive (
Pat_ID NVARCHAR(8)
,[status] TINYINT
)
INSERT INTO #SentReceive
VALUES ( 'Z1000354' ,1 )
,( 'Z1000354' ,1 )
,( 'Z1000363' ,1 )
,( 'Z1000363' ,2 )
,( 'Z1000392' ,2 )
,( 'Z1000394' ,1 )
,( 'Z1000394' ,2 )
SELECT pat_id
,sentstatus = CASE sum(distinct [status])
WHEN 1
THEN 'Sent'
WHEN 2
THEN 'Received'
WHEN 3
THEN 'Sent and Received'
END
FROM #SentReceive
GROUP BY pat_id
ORDER BY pat_id
create table SentReceive
(
Pat_ID nvarchar(8),
SentOnly nvarchar(8)
)
insert SentReceive
values
('Z1000354','Sent'),
('Z1000363','Sent'),
('Z1000363','Received'),
('Z1000392','Sent'),
('Z1000394','Sent'),
('Z1000394','Received')
select distinct a.Pat_ID,
case
when b.SentOnly is not null then
case a.SentOnly
when 'Received' then b.SentOnly + ' and ' + a.SentOnly
else a.SentOnly + ' and ' + b.SentOnly
end
else a.SentOnly
end as Status
from SentReceive a
left join SentReceive b on a.Pat_ID = b.Pat_ID and a.SentOnly <> b.SentOnly
I did a quickie with only the available data that you provided. If there are other variations in your dataset then you will need to account for that and it may or may not change what I came up with. Good luck!
Here is what I came up with:
;with cte as
(
select 1 as _order, 'Z1000354' as pat_id, 'Sent' as SentOnly
union select 2, 'Z1000363', 'Sent'
union select 3, 'Z1000363', 'Received'
union select 4, 'Z1000392', 'Sent'
union select 5, 'Z1000393', 'Received'
union select 5, 'Z1000394', 'Sent'
union select 6, 'Z1000394', 'Received'
)
select pat_id, replace(_Status,',',' and') as _Status
from(
select distinct pat_id,
STUFF((Select ', '+SentOnly
from cte T2
where T1.pat_id=T2.pat_id
FOR XML PATH('')),1,1,'') as _Status from cte T1
) a
where _Status in (' Sent', ' Sent, Received')
Final query with some help from above posters:
select distinct a.pat_id,
case when b.ADDR_MSG_ACTN_C is not null
then 'Sent and Received' else 'Sent Only' end as Status
from pat_addr_verif a
left join pat_addr_verif b on a.pat_id = b.pat_id and
a.ADDR_MSG_ACTN_C <> b.ADDR_MSG_ACTN_C
where a.pat_id in ('Z1000354','Z1000363','Z1000392','Z1000394')
Correct Final Output
I have a product table as below.
Where I want to get each product detail where its product_ship_flag is "YES" for all the products of same the order_number. If any of the product_ship_flag is "No" then the whole order_number should not be in the output. If all product_ship_flag as "No" then should not be in the output.
The Output will look like:
Thanks in advance.
Edited: Few members are not even trying to understand the problem, And some are not able to answer the problem so devoting the question. Please show some sportiness.
Try this.
If the inner query does not return anything for that order that means all the product has flag_ship equal to Yes
select * from product p
where not exists (
select '1' from product p2
where p2.order_number = p1.order_number
and p2.product_ship_flag = 'No')
Isn't that a basic query like this works?
Select * from product where product_ship_flag = 'Yes' group by order_number
Try with this query:
select * from product where orderno not in (select orderno, count(case when product_ship_flaf='No' then 1 end) from product
group by orderno
having count(case when product_ship_flaf='No' then 1 end)>=1)A
#irfan_m, the logic can be captured with the MIN operator. When you do a subquery and using a column called flag for example. You can easily pull out the orders based on your requirement.
See a mock up below:
DECLARE #Producttbl TABLE (id int, order_number varchar(20), product_id varchar(20), stock_cnt int, product_ship_flag VARCHAR(3))
INSERT INTO #Producttbl
SELECT 1,'001','SKU1', 1, 'Yes' union all
SELECT 2,'001','SKU2', 2, 'Yes' union all
SELECT 3,'001','SKU3', 1, 'No' union all
SELECT 4,'002','SKU1', 1, 'Yes' union all
SELECT 5,'002','SKU2', 2, 'Yes' union all
SELECT 6,'003','SKU1', 1, 'No' union all
SELECT 7,'003','SKU2', 2, 'No'
SELECT *
FROM
#Producttbl P
JOIN (
SELECT order_number, Flag=MIN(product_ship_flag)
--product_ship_flag is
---"YES" : for all the products of same the order_number
--If any of the product_ship_flag is "No" then the whole order_number should not be in the output.
--If all product_ship_flag as "No" then should not be in the output.
FROM
#Producttbl
GROUP BY
order_number
)S ON
S.order_number=P.order_number
WHERE
S.Flag='Yes'
see result below:
A left join could be handy in this case.
DECLARE #ProducttblTEST TABLE (id int, order_number varchar(20), product_id
varchar(20), stock_cnt int, product_ship_flag VARCHAR(3))
INSERT INTO #ProducttblTEST
SELECT 1,'001','SKU1', 1, 'Yes' union all
SELECT 2,'001','SKU2', 2, 'Yes' union all
SELECT 3,'001','SKU3', 1, 'No' union all
SELECT 4,'002','SKU1', 1, 'Yes' union all
SELECT 5,'002','SKU2', 2, 'Yes' union all
SELECT 6,'003','SKU1', 1, 'No' union all
SELECT 7,'003','SKU2', 2, 'No'
select * from #ProducttblTEST a
left join (select * from #ProducttblTEST where product_ship_flag = 'no') b on
a.order_number = b.order_number
where a.product_ship_flag = 'yes' and b.order_number is null
Suppose I have a table with columns user_id, name and the table contains data like this:
user_id name
------- -----
sou souhardya
cha chanchal
swa swapan
ari arindam
ran ranadeep
If I want to know these users (sou, cha, ana, agn, swa) exists in this table or not then I want output like this:
user_id it exists or not
------- -----------------
sou y
cha y
ana n
agn n
swa y
As ana and aga do not exist in the table it must show "n" (like the above output).
Assuming your existing checklist is not on the database, you will have to assemble a query containing those. There are many ways of doing it. Using CTEs, it would look like this:
with cte as
(
select 'sou' user_id
union all
select 'cha'
union all
select 'ana'
union all
select 'agn'
union all
select 'swa'
)
select
cte.user_id,
case when yt.user_id is null then 'n' else 'y' end
from cte
left join YourTable yt on cte.user_id = yt.user_id
This also assumes user_id is unique.
Here is the SQLFiddle with the proof of concept: http://sqlfiddle.com/#!3/e023a0/4
Assuming you're just testing this manually:
DECLARE #Users TABLE
(
[user_id] VARCHAR(50)
)
INSERT INTO #Users
SELECT 'sou'
UNION SELECT 'cha'
UNION SELECT 'ana'
UNION SELECT 'agn'
UNION SELECT 'swa'
SELECT a.[user_id]
, [name]
, CASE
WHEN b.[user_id] IS NULL THEN 'N'
ELSE 'Y'
END AS [exists_or_not]
FROM [your_table] a
LEFT JOIN #Users b
ON a.[user_id] = b.[user_id]
You didn't provide quite enough information to provide a working example, but this should get you close:
select tbl1.user_id, case tbl2.user_id is null then 'n' else 'y' end
from tbl1 left outer join tbl2 on tbl1.user_id = tbl2.user_id
;with usersToCheck as
(
select 'sou' as userid
union select 'cha'
union select 'ana'
union select 'agn'
union select 'swa'
)
select utc.userid,
(case when exists ( select * from usersTable as ut where ut.user_id = utc.userid) then 'y' else 'n' end)
from usersToCheck as utc
I know you've got multiple topics touching on this. But, I havent found one that addressed my needs. I need to (on demand) pivot select deep table data to a wide output table. The gotcha in this is that I cannot use an aggregate with Pivot because it eats responses that are needed in the output. I have worked up to a solution, but I don't think it's the best because it will require umpteen left joins to work. I've included all attempts and notes as follows:
-- Sql Server 2008 db.
-- Deep table structure (not subject to modification) contains name/value pairs with a userId as
-- foreign key. In many cases there can be MORE THAN ONE itemValue given by the user for the
-- itemName such as if asked their race, can answer White + Hispanic, etc. Each response is stored
-- as a seperate record - this cannot currently be changed.
-- Goal: pivot deep data to wide while also compressing result
-- set down. Account for all items per userId, and duplicating
-- column values (rather than show nulls) as applicable
-- Sample table to store some data of both single and multiple responses
DECLARE #testTable AS TABLE(userId int, itemName varchar(50), itemValue varchar(255))
INSERT INTO #testTable
SELECT 1, 'q01', '1-q01 Answer'
UNION SELECT 1, 'q02', '1-q02 Answer'
UNION SELECT 1, 'q03', '1-q03 Answer 1'
UNION SELECT 1, 'q03', '1-q03 Answer 2'
UNION SELECT 1, 'q03', '1-q03 Answer 3'
UNION SELECT 1, 'q04', '1-q04 Answer'
UNION SELECT 1, 'q05', '1-q05 Answer'
UNION SELECT 2, 'q01', '2-q01 Answer'
UNION SELECT 2, 'q02', '2-q02 Answer'
UNION SELECT 2, 'q03', '2-q03 Answer 1'
UNION SELECT 2, 'q03', '2-q03 Answer 2'
UNION SELECT 2, 'q04', '2-q04 Answer'
UNION SELECT 2, 'q05', '2-q05 Answer'
SELECT 'Raw Data'
SELECT * FROM #TestTable
SELECT 'Using Pivot - shows aggregate result of itemValue per itemName - eats others'
; WITH Data AS (
SELECT
[userId]
, [itemName]
, [itemValue]
FROM
#testTable
)
SELECT
[userId]
, [q02]
, [q03]
, [q05]
FROM
Data
PIVOT
(
MIN(itemValue) -- Aggregate function eats needed values.
FOR itemName in ([q02], [q03], [q05])
) AS PivotTable
SELECT 'Aggregate with Grouping - Causes Null Values'
SELECT
DISTINCT userId
,[q02] = Max(CASE WHEN itemName = 'q02' THEN itemValue END)
,[q03] = Max(CASE WHEN itemName = 'q03' THEN itemValue END)
,[q05] = Max(CASE WHEN itemName = 'q05' THEN itemValue END)
FROM
#testTable
WHERE
itemName in ('q02', 'q03', 'q05') -- Makes it a hair quicker
GROUP BY
userId -- If by userId only, it only gives 1 row PERIOD = BAD!!
, [itemName]
, [itemValue]
SELECT 'Multiple Left Joins - works properly but bad if pivoting 175 columns or so'
; WITH Data AS (
SELECT
userId
,[itemName]
,[itemValue]
FROM
#testTable
WHERE
itemName in ('q02', 'q03', 'q05') -- Makes it a hair quicker
)
SELECT
DISTINCT s1.userId
,[q02] = s2.[itemValue]
,[q03] = s3.[itemValue]
,[q05] = s5.[itemValue]
FROM
Data s1
LEFT JOIN Data s2
ON s2.userId = s1.userId
AND s2.[itemName] = 'q02'
LEFT JOIN Data s3
ON s3.userId = s1.userId
AND s3.[itemName] = 'q03'
LEFT JOIN Data s5
ON s5.userId = s1.userId
AND s5.[itemName] = 'q05'
So the bottom query is the only one (so far) that does what I need it to do, but the LEFT JOIN's WILL get out of hand and cause performance issues when I use actual item names to pivot. Any recommendations are appreciated.
I think you'll have to stick with joins, because joins are exactly the way of producing results like the one you are after. The purpose of a join is to combine row sets together (on a condition or without any), and your target output is nothing else than a combination of subsets of rows.
However, if the majority of questions always have single responses, you could substantially reduce the number of necessary joins. The idea is to join only multiple-response groups as separate row sets. As for the single-response items, they are joined only as part of the entire dataset of target items.
An example should better illustrate what I might poorly describe verbally. Assuming there are two potentially multiple-response groups in the source data, 'q03' and 'q06' (actually, here's the source table:
DECLARE #testTable AS TABLE(
userId int,
itemName varchar(50),
itemValue varchar(255)
);
INSERT INTO #testTable
SELECT 1, 'q01', '1-q01 Answer'
UNION SELECT 1, 'q02', '1-q02 Answer'
UNION SELECT 1, 'q03', '1-q03 Answer 1'
UNION SELECT 1, 'q03', '1-q03 Answer 2'
UNION SELECT 1, 'q03', '1-q03 Answer 3'
UNION SELECT 1, 'q04', '1-q04 Answer'
UNION SELECT 1, 'q05', '1-q05 Answer'
UNION SELECT 1, 'q06', '1-q06 Answer 1'
UNION SELECT 1, 'q06', '1-q06 Answer 2'
UNION SELECT 1, 'q06', '1-q06 Answer 3'
UNION SELECT 2, 'q01', '2-q01 Answer'
UNION SELECT 2, 'q02', '2-q02 Answer'
UNION SELECT 2, 'q03', '2-q03 Answer 1'
UNION SELECT 2, 'q03', '2-q03 Answer 2'
UNION SELECT 2, 'q04', '2-q04 Answer'
UNION SELECT 2, 'q05', '2-q05 Answer'
UNION SELECT 2, 'q06', '2-q06 Answer 1'
UNION SELECT 2, 'q06', '2-q06 Answer 2'
;
which is same as the table in the original post, but with added 'q06' items), the resulting script could be like this:
WITH ranked AS (
SELECT
*,
rn = ROW_NUMBER() OVER (PARTITION BY userId, itemName ORDER BY itemValue)
FROM #testTable
),
multiplied AS (
SELECT
r.userId,
r.itemName,
r.itemValue,
rn03 = r03.rn,
rn06 = r06.rn
FROM ranked r03
INNER JOIN ranked r06 ON r03.userId = r06.userId AND r06.itemName = 'q06'
INNER JOIN ranked r ON r03.userId = r.userId AND (
r.itemName = 'q03' AND r.rn = r03.rn OR
r.itemName = 'q06' AND r.rn = r06.rn OR
r.itemName NOT IN ('q03', 'q06')
)
WHERE r03.itemName = 'q03'
AND r.itemName IN ('q02', 'q03', 'q05', 'q06')
)
SELECT userId, rn03, rn06, q02, q03, q05, q06
FROM multiplied
PIVOT (
MIN(itemValue)
FOR itemName in (q02, q03, q05, q06)
) AS PivotTable
; WITH SRData AS (
SELECT -- Only query single response items in this block
[userId]
, [q01]
, [q02]
, [q04]
, [q05]
FROM
#testTable
PIVOT
(
MIN(itemValue)
FOR itemName in ([q01], [q02], [q04], [q05])
) AS PivotTable
)
SELECT
sr.[userId]
, sr.[q01]
, sr.[q02]
, [q03] = mr03.[itemValue]
, sr.[q04]
, sr.[q05]
, [q06] = mr06.[itemValue]
FROM
SRData sr
LEFT JOIN #testTable mr03 ON mr03.userId = sr.userId AND mr03.itemName = 'q03' -- Muli Response for q03
LEFT JOIN #testTable mr06 ON mr06.userId = sr.userId AND mr06.itemName = 'q06' -- Muli Response for q06
Not clear what the desired results should look like exactly but one possibility
; WITH Data AS (
SELECT
ROW_NUMBER() OVER (PARTITION BY [userId], [itemName]
ORDER BY [itemValue]) AS RN
, [userId]
, [itemName]
, [itemValue]
FROM
#testTable
)
SELECT
[userId]
, [q02]
, [q03]
, [q05]
FROM
Data
PIVOT
(
MIN(itemValue)
FOR itemName in ([q02], [q03], [q05])
) AS PivotTable
Returns
userId q02 q03 q05
----------- ------------------------------ ------------------------------ ------------------------------
1 1-q02 Answer 1-q03 Answer 1 1-q05 Answer
1 NULL 1-q03 Answer 2 NULL
1 NULL 1-q03 Answer 3 NULL
2 2-q02 Answer 2-q03 Answer 1 2-q05 Answer
2 NULL 2-q03 Answer 2 NULL
I am trying to merge 2 databases with the same schema together, and this is one part of it.
I have changed the subject to keep it more understandable - I cannot change this schema, it's just what I'm working with.
I have a table in both my source and target databases with the following columns:
Car
CarType1
CarType2
CarType3
CarType4
I am trying to write a query that will tell me in the target database, which rows have the same Cars between the 2 databases, but different CarTypes. All I need is a count on the rows that are different.
My query written in english would be:
Bring me back a count of rows where the Car is the same and the CarTypes between the two systems do not match. It doesn't matter if the CarType is in a different CarType field between the two, just whether all of the values are contained in one of the 4 fields or not.
So if in my source database this row:
Car: Mustang
CarType1: Fast
CarType2: Convertible
CarType3: null
CarType4: null
And in my target database I have this row:
Car: Mustang
CarType1: Fast
CarType2: Convertible
CarType3: Sports
CarType4: null
This would count as a non-match, since it's a Mustang and because the aggregate of the CarType fields is different. What order the values are in does not matter for this.
How would I write this query? I cannot get a grasp on it.
;WITH SourceT AS (
SELECT 'Toyota' AS Car, 'A' AS CarType1, 'B' AS CarType2, 'C' CarType3, 'D' CarType4 UNION ALL
SELECT 'BMW' AS Car, 'A' AS CarType1, 'B' AS CarType2, 'C' CarType3, 'D' CarType4 UNION ALL
SELECT 'Mustang' AS Car, 'Fast' AS CarType1, 'Convertible' AS CarType2, 'Sports' CarType3, NULL CarType4
),
TargetT AS (
SELECT 'Toyota' AS Car, 'D' AS CarType1, 'C' AS CarType2, 'B' CarType3, 'A' CarType4 UNION ALL
SELECT 'BMW' AS Car, 'D' AS CarType1, 'C' AS CarType2, 'B' CarType3, 'A' CarType4 UNION ALL
SELECT 'Mustang' AS Car, 'Fast' AS CarType1, 'Convertible' AS CarType2, NULL CarType3, NULL CarType4 )
SELECT *
FROM SourceT s
WHERE NOT EXISTS
(
SELECT *
FROM TargetT t
WHERE s.Car = t.Car AND 0 =
(SELECT COUNT(*) FROM
( (
(SELECT s.CarType1 AS t UNION ALL
SELECT s.CarType2 AS t UNION ALL
SELECT s.CarType3 AS t UNION ALL
SELECT s.CarType4 AS t )
EXCEPT
(SELECT t.CarType1 AS t UNION ALL
SELECT t.CarType2 AS t UNION ALL
SELECT t.CarType3 AS t UNION ALL
SELECT t.CarType4 AS t )
)
UNION ALL
(
(SELECT t.CarType1 AS t UNION ALL
SELECT t.CarType2 AS t UNION ALL
SELECT t.CarType3 AS t UNION ALL
SELECT t.CarType4 AS t )
EXCEPT
(SELECT s.CarType1 AS t UNION ALL
SELECT s.CarType2 AS t UNION ALL
SELECT s.CarType3 AS t UNION ALL
SELECT s.CarType4 AS t )
)
) T
)
)
Or a slightly shorter version
SELECT *
FROM SourceT s
WHERE NOT EXISTS
(
SELECT *
FROM TargetT t
WHERE s.Car = t.Car AND
(SELECT t FROM (SELECT s.CarType1 AS t UNION ALL
SELECT s.CarType2 AS t UNION ALL
SELECT s.CarType3 AS t UNION ALL
SELECT s.CarType4 AS t ) D ORDER BY t FOR XML PATH(''))=
(SELECT t FROM (SELECT t.CarType1 AS t UNION ALL
SELECT t.CarType2 AS t UNION ALL
SELECT t.CarType3 AS t UNION ALL
SELECT t.CarType4 AS t ) D ORDER BY t FOR XML PATH(''))
)
Try this and let me know if it works:
SELECT * FROM db1.dbo.Cars
EXCEPT
SELECT c1.* FROM db1.dbo.Cars as c1
INNER JOIN db2.dbo.Cars as c2
ON c1.Car = c2.Car
AND
--Check carType1
(c1.CarType1 = c2.CarType1 OR
c1.CarType1 = c2.CarType2 OR
c1.CarType1 = c2.CarType3 OR
c1.CarType1 = c2.CarType4)
AND
--Check carType2
(c1.CarType2 = c2.CarType1 OR
c1.CarType2 = c2.CarType2 OR
c1.CarType2 = c2.CarType3 OR
c1.CarType2 = c2.CarType4)
AND
--Check carType3
(c1.CarType3 = c2.CarType1 OR
c1.CarType3 = c2.CarType2 OR
c1.CarType3 = c2.CarType3 OR
c1.CarType3 = c2.CarType4)
AND
--Check carType4
(c1.CarType4 = c2.CarType1 OR
c1.CarType4 = c2.CarType2 OR
c1.CarType4 = c2.CarType3 OR
c1.CarType4 = c2.CarType4)
NOTE:
You will have to add ISNULLs to this to either include or exclude if a column is null.
To exclude:
ISNULL(c1.CarType4, -1) = ISNULL(c2.CarType4, -2)
To include:
ISNULL(c1.CarType4, -1) = ISNULL(c2.CarType4, -1)
SELECT c1.car
FROM target.cars c1
INNER JOIN source.cars c2
ON c2.car = c1.car
WHERE
COALESCE( c1.cartype1, '') NOT IN
( '', c2.cartype1, c2.cartype2, c2.cartype3, c2.cartype4 )
OR
COALESCE( c1.cartype2, '') NOT IN
( '', c2.cartype1, c2.cartype2, c2.cartype3, c2.cartype4 )
OR
COALESCE( c1.cartype3, '') NOT IN
( '', c2.cartype1, c2.cartype2, c2.cartype3, c2.cartype4 )
OR
COALESCE( c1.cartype4, '') NOT IN
( '', c2.cartype1, c2.cartype2, c2.cartype3, c2.cartype4 )
OR
LEN( COALESCE( c1.cartype1, '') + COALESCE( c1.cartype2, '') +
COALESCE( c1.cartype3, '') + COALESCE( c1.cartype4, '') )
<>
LEN( COALESCE( c2.cartype1, '') + COALESCE( c2.cartype2, '') + COALESCE( c2.cartype3, '') +
COALESCE( c2.cartype4, '') )
;