Select data from query1 where option = and != together - sql

help me please.
I having result set (table). To get the this first result set, I make a selection with three joins. To get all the necessary characteristics of the goods ( 05_A and 05_B and some descriptions)
We can see stock items.
for example:
artid | warehousetype
001 | 05_A
001 | 05_B
002 | 05_A
I need to select all artid where warehouse type in 05_A and not in 05_B (ex. 002)
I'm try:
select * from table where warehousetype like 05_A and warehousetype not like 05_A - it's not work.
I'm try
select * from table where warehousetype like 05_A
MINUS
select * from table where warehousetype like 05_B
it's works but i'm see all stock w\o 05_B, but need see only artid where whtype = 05_A and not 05_B
How do make my report?

You can use the NOT EXISTS clause along with a subquery to achieve the desired result.
SELECT artid
FROM table
WHERE warehousetype = '05_A'
AND NOT EXISTS (
SELECT artid
FROM table table2
WHERE warehousetype = '05_B'
AND table.artid = table2.artid
);
You can also use a JOIN with a negation condition on the joined table to get the same result.
SELECT t1.artid
FROM table t1
LEFT JOIN table t2 on t1.artid = t2.artid and t2.warehousetype = '05_B'
WHERE t1.warehousetype = '05_A'
AND t2.artid is null

You can use Oracle's MINUS operator, to subtract all "artid" values that have '05_B' from all records that have '05_A'.
SELECT artid FROM tab WHERE warehousetype = '05_A'
MINUS
SELECT artid FROM tab WHERE warehousetype IN ('05_B')
Check the demo here.

With your sample data ...
ARTID
WAREHOUSETYPE
001
05_A
001
05_B
002
05_A
...you could use LISTAGG analytic function to get a list of warehouse types per ARTID:
SELECT ARTID, WAREHOUSETYPE,
LISTAGG(WAREHOUSETYPE, ', ') WITHIN GROUP (Order By WAREHOUSETYPE) OVER(Partition By ARTID) "WH_LIST"
FROM tbl
ARTID
WAREHOUSETYPE
WH_LIST
001
05_A
05_A, 05_B
001
05_B
05_A, 05_B
002
05_A
05_A
With this WH_LIST you can use LIKE and NOT LIKE ...
SELECT ARTID, WAREHOUSETYPE
FROM ( SELECT ARTID, WAREHOUSETYPE,
LISTAGG(WAREHOUSETYPE, ', ') WITHIN GROUP (Order By WAREHOUSETYPE) OVER(Partition By ARTID) "WH_LIST"
FROM tbl )
WHERE WH_LIST LIKE '%05_A%' And WH_LIST NOT LIKE '%05_B%'
Result:
ARTID
WAREHOUSETYPE
002
05_A

This is the simplest possible way to do this. In the inner query you get every art id with warehouse '05_B' with it. Then you exclude all those ids from the list of ids where warehousetype '05_A' matches with.
SELECT artid FROM table
WHERE warehousetype = '05_A' AND artid
NOT IN(
SELECT artid
FROM table
WHERE warehousetype = '05_B'
);
I did not test it so please correct if there is any syntax issues or whatsoever. Except for that its should be working perfectly.

Related

Find the difference of values between 2 columns after joining 2 tables on ms sql server

I have 2 tables in MS SQL Server 2019 - test1 and test2. Below are the table creation and insert statements for the 2 tables :
create table test2 (id nvarchar(10) , code nvarchar(5) , all_names nvarchar(80))
create table test3 (code nvarchar(5), name1 nvarchar(18) )
insert into test2 values ('A01', '50493', '12A2S0403-Buffalo;13A1T0101-Boston;13A2C0304-Miami')
insert into test2 values ('A02', '31278', '12A1S0205-Detroit')
insert into test2 values ('A03', '49218', '12A2S0403-Buffalo;12A1M0208-Manhattan')
insert into test3 values ('50493', 'T0101-Boston')
insert into test3 values ('49218', 'S0403-Buffalo')
insert into test3 values ('31278', 'S0205-Detroit')
I can join the 2 tables on the code column. Task is to find difference of test2.all_names and test3.name1. For example 'A01' should display the result as '12A2S0403-Buffalo;13A2C0304-Miami'.
A02 should not come as output.
The output should be :
Id | Diff_of_name
----------------------------------------
A01 | 12A2S0403-Buffalo;13A2C0304-Miami
A03 | 12A1M0208-Manhattan
Here's one possible solution, first using openjson to split your source string into rows, then using exists to check for matching values in table test3 and finally string_agg to provide the final result:
select Id, String_Agg(j.[value], ';') within group (order by j.seq) Diff_Of_Name
from test2 t2
cross apply (
select j.[value], Convert(tinyint,j.[key]) Seq
from OpenJson(Concat('["',replace(all_names,';', '","'),'"]')) j
where not exists (
select * from test3 t3
where t3.code = t2.code and j.[value] like Concat('%',t3.name1,'%')
)
)j
group by t2.Id;
Demo Fiddle
I don't like the need to normalize. However, if one must normalize, STRING_SPLIT is handy.
When done with the real work, STRING_AGG can de-normalize the data.
WITH normalized as ( -- normalize all_names in test2 to column name1
SELECT t2.id, t2.code, t2.all_names, n.value as [name1]
FROM test2 t2
OUTER APPLY STRING_SPLIT(t2.all_names, ';') n
) select * from normalized;
WITH normalized as ( -- normalize all_names in test2 to column name1
SELECT t2.id, t2.code, t2.all_names, n.value as [name1]
FROM test2 t2
OUTER APPLY STRING_SPLIT(t2.all_names, ';') n
), differenced as ( -- exclude name1 values listed in test3, ignoring leading characters
SELECT n.*
FROM normalized n
WHERE NOT EXISTS(SELECT * FROM test3 t3 WHERE t3.code = n.code AND n.name1 LIKE '%' + t3.name1)
) -- denormalize
SELECT id, STRING_AGG(name1, ';') as [Diff_of_name]
FROM differenced
group by id
order by id
id Diff_of_name
---------- ---------------------------------
A01 12A2S0403-Buffalo;13A2C0304-Miami
A03 12A1M0208-Manhattan

Finding a dynamic intersection of a table

I have a query that will return some results like
London 111
London 222
London 333
Manchester 333
Liverpool 111
Liverpool 222
Liverpool 333
Leeds 111
Leeds 222
Leeds 333
My stored procedure takes in a user defined table that is a list of codes like
111 and 222, but it could take in any number of codes depending on user input from a website
Given that 111 and 333 are passed in I want the SP to return London, Liverpool and Leeds (not manchester) because
They all have records with both these codes
Any clues on how I can achieve this?
Thanks!
Assuming you have two tables like this:
CREATE table towns (town varchar(16), code int);
insert into towns values
('London', 111),('London', 222),
('London', 333),('Manchester', 333),
('Liverpool', 111),('Liverpool', 222),
('Liverpool', 333),('Leeds', 111),
('Leeds' ,222),('Leeds',333);
create table codes (ccde int);
insert into codes values (111),(333);
You should try
SELECT town, code FROM towns INNER JOIN codes on ccde=code GROUP BY town
HAVING COUNT(*)=(select count(*) from codes)
Please check out this edited version. My first try was obviously wrong.
You can find a demo here: http://rextester.com/DCWD90908
Edit
Just noticed that my command would give wrong results if there isn't a unique restriction on the columns town, code in towns. In case there can be double records in towns, like 'Manchester', 333 appearing twice, then the following will still deliver the right results:
SELECT town FROM
(SELECT DISTINCT * FROM towns) t
INNER JOIN codes ON ccde=code GROUP BY town
HAVING COUNT(*)=(SELECT DISTINCT COUNT(*) FROM codes)
http://rextester.com/RZJK41394
Throw the query results into a temporary table and re-query it like this.
You can do a basic SELECT query.
SELECT name , code
FROM [table] AS t1
INNER JOIN [table] AS t2
ON t1.name = t2.name
WHERE t1.code = '111' AND t2.code = '333'
This will get inefficient for larger data sets though.
Another method would be to use ROW_NUMBER() and a sub-SELECT.
SELECT DISTINCT name FROM (
SELECT name , ROW_NUMBER () OVER (PARTITION BY name ORDER BY code) AS row_count
FROM [table] AS t1
WHERE t1.code IN ('333' , '111')
GROUP BY t1.name, t1.code ) AS list
WHERE list.row_count > 1

Rearranging values from a pivot table

I am using SQL Server 2012, self-taught so sorry for any errors/mistakes.
I have a table that I had pivot and the resulting table has null values like so:
Pepsi Coke Gatorade
--------------------------
Vanilla NULL NULL
Cherry NULL NULL
NULL Vanilla NULL
NULL Cherry NULL
NULL NULL Lime
NULL NULL Fruit Punch
NULL NULL Grape
My question is if there is a way to rearrange the table so that the rows that are not null show up at the top of their respective columns in such a way so that if another user was to add a different type of drink, such as water, that the query would be to automatically sort the newly added column. If this cannot be accomplished then an alternative suggestion would be appreciated.
An example of the desired result would be like so:
Pepsi Coke Gatorade
------------------------------
Vanilla Vanilla Lime
Cherry Cherry Fruit Punch
NULL NULL Grape
I have tried doing a series of outer joins from the FROM clause however, I cannot figure out a way to generate the results without explicitly calling the columns and/or table names.
select distinct t1.Pepsi, t2.Coke from
(select
#test.Pepsi as Pepsi,
ROW_NUMBER() over (order by Pepsi) r
from #test
where Pepsi is not null) as t1
full outer join
(select
#test.Coke as Coke,
ROW_NUMBER() over (order by Coke) r
from #test
where Coke is not null) as t2
on t1.r=t2.r
The original table looks like so:
Drink Type Price Location etc
Coke Vanilla
Coke Cherry
Gatorade Lime
Gatorade Grape
.
.
.
Pepsi Cherry
Any advice or help is greatly appreciated.
DECLARE #t TABLE ([Drink] varchar(max), [Type] varchar(max), [Price] money )
INSERT #t
([Drink],[Type])
VALUES
('Coke','Vanilla'),
('Coke','Cherry'),
('Gatorade','Lime'),
('Gatorade','Grape'),
('Gatorade','Fruit Punch'),
('Pepsi','Vanilla'),
('Pepsi','Cherry')
;WITH t AS (
SELECT
[Drink],[Type],
ROW_NUMBER() OVER(PARTITION BY [Drink] ORDER BY [Type] DESC) rn
FROM #t
)
SELECT [Pepsi],[Coke],[Gatorade]
FROM t
PIVOT(MAX([Type]) FOR [Drink] IN ([Pepsi],[Coke],[Gatorade])) p

How to delete the Duplicate rows

Table1
ID Date
001 23/02/2009
001 24/02/2009
001 24/02/2009
002 25/02/2009
002 25/02/2009
...
I want to delete the duplicate rows from the above table.
Expected Output
ID Date
001 23/02/2009
001 24/02/2009
002 25/02/2009
...
Need Query Help
Can't remember where I got it, but I used to use this SQL to remove duplicates from a table:
begin tran deduplicate
select DISTINCT *
into #temp
from mytable
truncate table mytable
insert mytable
select *
from #temp
select * from mytable
drop table #temp
commit tran deduplicate
If you do google search you will get plenty of help.
E.g.
http://support.microsoft.com/kb/139444
http://blog.sqlauthority.com/2007/03/01/sql-server-delete-duplicate-records-rows/
http://www.sql-server-performance.com/2003/delete-duplicates/

Is it possible to use WHERE IN along with LIKE?

If I have to search for some data I can use wildcards and use a simple query -
SELECT * FROM TABLE WHERE COL1 LIKE '%test_string%'
And, if I have to look through many values I can use -
SELECT * FROM TABLE WHERE COL1 IN (Select col from AnotherTable)
But, is it possible to use both together. That is, the query doesn't just perform a WHERE IN but also perform something similar to WHERE LIKE? A query that just doesn't look through a set of values but search using wildcards through a set of values.
If this isn't clear I can give an example. Let me know. Thanks.
Example -
lets consider -
AnotherTable -
id | Col
------|------
1 | one
2 | two
3 | three
Table -
Col | Col1
------|------
aa | one
bb | two
cc | three
dd | four
ee | one_two
bb | three_two
Now, if I can use
SELECT * FROM TABLE WHERE COL1 IN (Select col from AnotherTable)
This gives me -
Col | Col1
------|------
aa | one
bb | two
cc | three
But what if I need -
Col | Col1
------|------
aa | one
bb | two
cc | three
ee | one_two
bb | three_two
I guess this should help you understand what I mean by using WHERE IN and LIKE together
SELECT *
FROM TABLE A
INNER JOIN AnotherTable B on
A.COL1 = B.col
WHERE COL1 LIKE '%test_string%'
Based on the example code provided, give this a try. The final select statement presents the data as you have requested.
create table #AnotherTable
(
ID int IDENTITY(1,1) not null primary key,
Col varchar(100)
);
INSERT INTO #AnotherTable(col) values('one')
INSERT INTO #AnotherTable(col) values('two')
INSERT INTO #AnotherTable(col) values('three')
create table #Table
(
Col varchar(100),
Col1 varchar(100)
);
INSERT INTO #Table(Col,Col1) values('aa','one')
INSERT INTO #Table(Col,Col1) values('bb','two')
INSERT INTO #Table(Col,Col1) values('cc','three')
INSERT INTO #Table(Col,Col1) values('dd','four')
INSERT INTO #Table(Col,Col1) values('ee','one_two')
INSERT INTO #Table(Col,Col1) values('ff','three_two')
SELECT * FROM #AnotherTable
SELECT * FROM #Table
SELECT * FROM #Table WHERE COL1 IN(Select col from #AnotherTable)
SELECT distinct A.*
FROM #Table A
INNER JOIN #AnotherTable B on
A.col1 LIKE '%'+B.Col+'%'
DROP TABLE #Table
DROP TABLE #AnotherTable
Yes. Use the keyword AND:
SELECT * FROM TABLE WHERE COL1 IN (Select col from AnotherTable) AND COL1 LIKE '%test_string%'
But in this case, you are probably better off using JOIN syntax:
SELECT TABLE.* FROM TABLE JOIN AnotherTable on TABLE.COL1 = AnotherTable.col WHERE TABLE.COL1 LIKE '%test_string'
no because each element in the LIKE clause needs the wildcard and there's not a way to do that with the IN clause
The pattern matching operators are:
IN, against a list of values,
LIKE, against a pattern,
REGEXP/RLIKE against a regular expression (which includes both wildcards and alternatives, and is thus closest to "using wildcards through a set of valuws", e.g. (ab)+a|(ba)+b will match all strings aba...ba or bab...ab),
FIND_IN_SET to get the index of a string in a set (which is represented as a comma separated string),
SOUNDS LIKE to compare strings based on how they're pronounced and
MATCH ... AGAINST for full-text matching.
That's about it for string matching, though there are other string functions.
For the example, you could try joining on Table.Col1 LIKE CONCAT(AnotherTable.Col, '%'), though performance will probably be dreadful (assuming it works).
Try a cross join, so that you can compare every row in AnotherTable to every row in Table:
SELECT DISTINCT t.Col, t.Col1
FROM AnotherTable at
CROSS JOIN Table t
WHERE t.col1 LIKE ('%' + at.col + '%')
To make it safe, you'll need to escape wildcards in at.col. Try this answer for that.
If I understand the question correctly you want the rows from "Table" when "Table.Col1" is IN "AnotherTable.Col" and you also want the rows when Col1 IS LIKE '%some_string%'.
If so you want something like:
SELECT
t.*
FROM
[Table] t
LEFT JOIN
[AnotherTable] at ON t.Col1 = at.Col
WHERE (at.Col IS NOT NULL
OR t.Col1 LIKE '%some_string%')
Something like this?
SELECT * FROM TABLE
WHERE
COL1 IN (Select col from AnotherTable)
AND COL1 LIKE '%test_string%'
Are you thinking about something like EXISTS?
SELECT * FROM TABLE t WHERE EXISTS (Select col from AnotherTable t2 where t2.col = t.col like '%test_string%' )