Pick each column value on different criteria - sql

I have a SQL Query as below:
SELECT urban_appr, urban_in, rural_appr, rural_in, ground_appr, ground_in
FROM <table>
In the above query, I have to add WHERE clause as follows:
For urban values, WHERE scheme_type = 'U'
For rural values, WHERE scheme_type = 'R'
For ground values, WHERE scheme_type = 'E'
I want all this using single SQL query. I am using SQL Server 2005.
Edited:
Added image below of the actual problem. You can see that it is showing district BR as two records, whereas I want it in one row.

Use JOIN to bring all rows for each district_nm into one row:
select
district_nm,
t1.urban_appr, t1.urban_in,
t2.rural_appr, t2.rural_in,
t3.ground_appr, t3.ground_in
from <table> t1
join <table> t2 on t2.district_nm = t1.district_nm and t2.scheme_type = 'R'
join <table> t3 on t3.district_nm = t1.district_nm and t3.scheme_type = 'E'
where t1.scheme_type = 'U';
You can add more conditions to the where clause as you like, eg and t1.district_nm = 'x'
Consider creating a view from the above query and use that in our app instead:
create view table_view as
<above query>

Are you trying to do something like this - selecting different columns depending on the type of your values??
SELECT urban_appr, urban_in, NULL, NULL, NULL, NULL
FROM dbo.YourTable WHERE scheme_type = 'U'
UNION
SELECT NULL, NULL, rural_appr, rural_in, NULL, NULL
FROM dbo.YourTable WHERE scheme_type = 'R'
UNION
SELECT NULL, NULL, NULL, NULL, ground_appr, ground_in
FROM dbo.YourTable WHERE scheme_type = 'E'
???
Update: so you want to add another column and group by it:
SELECT district_nm, urban_appr, urban_in, NULL, NULL, NULL, NULL
FROM dbo.YourTable WHERE scheme_type = 'U'
UNION
SELECT district_nm, NULL, NULL, rural_appr, rural_in, NULL, NULL
FROM dbo.YourTable WHERE scheme_type = 'R'
UNION
SELECT district_nm, NULL, NULL, NULL, NULL, ground_appr, ground_in
FROM dbo.YourTable WHERE scheme_type = 'E'
GROUP BY district_nm
Is that what you're looking for??

Well, this looks ugly - but try this...
SELECT ISNULL(district_nm,nm) district_nm,
URBAN_APPR,
URBAN_IN,
RURAL_APPR,
RURAL_IN,
ground_appr,
ground_in
FROM
(SELECT ISNULL(a.district_nm, b.district_nm) nm,
urban_appr,
urban_in,
rural_appr,
rural_in
FROM
(SELECT DISTRICT_NM,
URBAN_APPR,
URBAN_IN
FROM TABLE_NAME
WHERE SCHEME_TYPE = 'U'
) a
FULL OUTER JOIN (
(SELECT DISTRICT_NM,
RURAL_APPR,
RURAL_IN
FROM TABLE_NAME
WHERE SCHEME_TYPE = 'R'
)B)
ON a.district_nm = b.district_nm
) temp
FULL OUTER JOIN (
(SELECT DISTRICT_NM,
GROUND_APPR,
GROUND_IN
FROM TABLE_NAME
WHERE SCHEME_TYPE = 'E'
)c)
ON temp.nm = c.district_nm;

Related

sql SERVER - distinct selection based on priority columns

hello I would like to find a solution to solve my problem in a single request if possible.
For the moment I take all the records then I go through the lines one by one to eliminate what I don't want.
I have 2 tables : first table with links
the second with the prefered label for the url
the second table must be consulted keeping only the row with maximum priority
priority rules are
the current user then
the user group and finally
everyone.
if the hidden column is true, exclude any reference to the url
here is the expected result.
Unfortunately, I don't see any other solution than to multiply the conditions on several selects and unions.
if you have a idea to solve my problem, thank you in advance for your help
It appears as though you can rely on pref_id for the preference ordering, correct? If so, you could try:
SELECT *
FROM table2
INNER JOIN table1 ON table2.url_id = table1.url_id
QUALIFY ROW_NUMBER() OVER (
PARTITION BY table1.url
ORDER BY pref_id ASC
) = 1
This will partition by the url and then provide only the one with lowest pref_id.
I didn't test this SQL as I wasn't sure which RDBMS you're running on, but I used Rasgo to translate the SQL.
maybe of interest in this tricky query:
select so.*, table1.url from
(select distinct t.url_id,
(select pref_id from table2 s where s.url_id = t.url_id order by "user" is null, "group" is null limit 1) pref_id
from table2 t
where not exists(select 1 from table2 s where s.hide and s.url_id = t.url_id)
) ids
join table2 so on so.pref_id = ids.pref_id
join table1 ON table1.url_id = ids.url_id
order by so.url_id;
here is my solution but i think there is better to do.
in the condition's select, I built a column which gives a level note according to the priorities
DECLARE #CUR_USER VARCHAR(10) = 'ROBERT'
DECLARE #CUR_GROUP VARCHAR(10) = 'DEV'
DECLARE #TABLE1 TABLE (
URL_ID INT
,URLNAME VARCHAR(100)
);
DECLARE #TABLE2 TABLE (
PREF_ID INT
,URL_ID INT
,FAVORITE_LABEL VARCHAR(100)
,USER_GROUP VARCHAR(10)
,USER_CODE VARCHAR(10)
,HIDE_URL DECIMAL(1, 0) DEFAULT 0
);
INSERT INTO #TABLE1
VALUES
(1, 'https://stackoverflow.com/')
,(2, 'https://www.microsoft.com/')
,(3, 'https://www.apple.com/')
,(4, 'https://www.wikipedia.org/')
;
INSERT INTO #TABLE2
VALUES
(1000, 1, 'find everything', NULL, 'ROBERT', 0)
,(1001, 1, 'a question ? find the answer here', 'DEV', NULL, 0)
,(1002, 1, 'StackOverFlow', NULL, NULL, 0)
,(1003, 2, 'Windows', 'DEV', NULL, 0)
,(1004, 2, 'Microsoft', NULL, NULL, 0)
,(1005, 3, 'Apple', NULL, NULL, 0)
,(1006, 4, 'Free encyclopedia', NULL, 'ROBERT', 1)
,(1007, 4, 'Wikipedia', NULL, NULL, 0)
,(1008, 1, 'StackOverFlow FOR MAT', 'MAT', NULL, 0)
,(1009, 2, 'Microsoft FOR MAT', 'MAT', NULL, 0)
,(1010, 3, 'Apple', 'MAT', NULL, 1)
,(1011, 4, 'Wikipedia FOR MAT', 'MAT', NULL, 0)
,(1012, 1, 'StackOverFlow', NULL, 'JEAN', 1)
,(1013, 2, 'Microsoft ', NULL, 'JEAN', 0)
,(1014, 3, 'Apple', NULL, 'JEAN', 0)
,(1015, 4, 'great encyclopedia', NULL, 'JEAN', 0)
;
SELECT t2.* ,t1.URLName
FROM #TABLE1 t1
INNER JOIN #TABLE2 t2 ON t1.URL_ID = t2.URL_ID
WHERE EXISTS (
SELECT 1
FROM (
SELECT TOP (1) test.PREF_ID
,CASE
-- if I do not comment this case: jean from the MAT group will not see apple
-- WHEN Hide_Url = 1
-- THEN 3
WHEN USER_code IS NOT NULL
THEN 2
WHEN USER_GROUP IS NOT NULL
THEN 1
ELSE 0
END AS ROW_LEVEL
FROM #TABLE2 test
WHERE (
(
test.USER_GROUP IS NULL
AND test.user_group IS NULL
AND test.USER_code IS NULL
)
OR (test.USER_GROUP = #CUR_GROUP)
OR (test.USER_code = #CUR_USER)
)
AND t2.URL_ID = test.URL_ID
ORDER BY ROW_LEVEL DESC
) test
WHERE test.PREF_ID = t2.PREF_ID
AND Hide_Url = 0
)
Simply use an ORDER BY clause that puts the preferred row first. You can use this in the window function ROW_NUMBER and work with this or use a lateral top(1) join with CROSS APPLY.
select *
from urls
cross apply
(
select top(1) *
from labels
where labels.url_id = urls.url_id
where [Group] is not null or [user] is not null or hide is not null
order by
case when [Group] is null then 2 else 1 end,
case when [user] is null then 2 else 1 end,
case when hide is null then 2 else 1 end
) top_labels
order by urls.url_id;

SQL Server SQL Statement - Updating record

I have a data as below:
I need to update Matching_id and Matching_Type by using column id, region, company, dept, subdept and amountsepend. The logic is:
Sum AmountSepend by Region, Company, Dept and SubDept. If the sum amount is 0 then Matching_Type is 'Match' and Matching_id is the combination of the id for the matched record else 'Not Match' and Matching_id is the id. **SUM means the total sum of all records for same criteria regardless the AmountSepend is positive or negative.
Another important criteria is if the transaction is single record, meaning the total count by grouping by Region, Company, Dept and SubDept is 1 then Matching type is Not Match and Matching_UID is id regardless the AmountSepend is 0 or positive/negative value. Example id 8.
Below is the output:
Here the table and data script
CREATE TABLE [dbo].[StackoverflowQuest](
[id] [int] NOT NULL,
[Region] [varchar](50) NULL,
[Company] [varchar](50) NULL,
[Dept] [varchar](50) NULL,
[SubDept] [varchar](50) NULL,
[AmountSepend] [float] NULL,
[Matching_id] [varchar](100) NULL,
[Matching_Type] [varchar](100) NULL
) ON [PRIMARY]
How could I achieved such result ? Any help/hint would be appreciate
CREATE TABLE #Table(Id INT,Region VARCHAR(100),Company INT,Dept INT,SubDept
INT,AmtSpend INT,MatchingId VARCHAR(100),MatchingType VARCHAR(100))
INSERT INTO #Table(Id ,Region ,Company , Dept ,SubDept ,AmtSpend )
SELECT 1,'NAM',12378,1,NULL,900 UNION ALL
SELECT 2,'NAM',12378,1,NULL,-900 UNION ALL
SELECT 3,'NAM',12370,1,23,1000 UNION ALL
SELECT 4,'ASA',1234,9,12,5000 UNION ALL
SELECT 5,'NAM',12370,1,23,-1000 UNION ALL
SELECT 6,'ASA',1234,9,12,800 UNION ALL
SELECT 7,'ASA',1234,9,12,-600 UNION ALL
SELECT 8,'ASA',12311,6,NULL,200
UPDATE #Table SET MatchingId = MatchIds,MatchingType = 'Match'
FROM
(
SELECT T2.Company,STUFF( ( SELECT ',' + CAST(T3.Id AS VARCHAR) FROM #Table
T3 WHERE T2.Company = T3.Company FOR XML PATH('')),1,1,'') MatchIds
FROM #Table T2
JOIN
(
SELECT T1.Company Company,SUM(T1.AmtSpend) Total
FROM #Table T1
GROUP BY T1.Company
HAVING SUM(T1.AmtSpend) = 0
)A ON A.Company = T2.Company
GROUP BY T2.Company
) A
WHERE A.Company = #Table.Company
UPDATE #Table SET MatchingId = CAST(Id AS VARCHAR),MatchingType = 'Not
Match' WHERE ISNULL(MatchingId,'') = ''
SELECT * FROM #Table

Why does my insert for new records only does not work even if I'm using where not exits to a subquery?

This is the script I used to create the table.
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[ODSCustomerBase]') AND type in (N'U'))
DROP TABLE [ODSCustomerBase]
Go
Create Table ODSCustomerBase
(CustomerBaseID int NOT NULL identity primary key,
RecordSource nvarchar(4),
RecordType varchar(2),
SiteURN nvarchar(128)NOT NULL,
SiteDesc nvarchar(60)NULL,
CustomerLink nvarchar(120)NOT NULL,
HomeCurrencyCode nvarchar(8)NOT NULL,
CustomerID nvarchar(15)NOT NULL,
CustomerCurrencyCode nvarchar(8)NOT NULL,
CustomerName nvarchar(120)NULL,
CustomerShortName nvarchar(30) NOT NULL,
Address nvarchar(255)NULL,
City nvarchar(25)NULL,
PostalCode nvarchar(10) NULL,
CountryCode nvarchar(3) NOT NULL,
CountryName nvarchar(60) NOT NULL,
StateCode nvarchar(8) NULL,
StateName nvarchar(60) NULL,
Phone nvarchar(30) NOT NULL,
Fax nvarchar(30) NULL,
TaxCode nvarchar(15) NULL,
ProspectID nvarchar(15) NULL,
CreateDate datetime NOT NULL,
LastUpdateDate datetime NULL)
This is the script I used to insert records for the first time
insert into SEC_ODS.dbo.ODSCustomerBase
select
--Identity as CustomerBaseID
'E4SE' as Recordsource, --could be others, eg 'BST', CRM, nvarchar(4)'
'C' as RecordType, --could be 'p'as prospects, add a case statement
ss.siteURN,
ss.sitedesc,
ss.FS_URL + 'frmcustomer.aspx?CustomerID=' + customerid as CustomerLink,
co.HomeCurrencyCode,
c.customerid,
c.currencycode as customercurrencycode,
c.entityname as CustomerName,
c.entityshortname CustomerShortName,
c.address,
c.city,
c.postalcode,
c.countrycode,
cn.countryname,
c.statecode,
s.statename,
c.phone,
c.fax,
c.taxcode,
c.prospectid,
c.createdate,
c.lastupdatedate
from country cn,
SECSite ss,
company co,
customer c
left outer join state s
on c.statecode = s.statecode
where ss.LocalSiteFlag = 1
and cn.countrycode = c.countrycode
So if I check the ODS table using this script, it gives me 4395 results
use sec_ods
go
select count(*) from ODSCustomerBase
While this is the script that I use to insert NEW RECORDS ONLY. This is where I used the where not exist condition and the sub query which doesn't work because it doubles the number of records. The goal is to insert only new records.
insert into SEC_ODS.dbo.ODSCustomerBase
select
--Identity as CustomerBaseID
'E4SE' as Recordsource, --could be others, eg 'BST', CRM, nvarchar(4)'
'C' as RecordType, --could be 'p'as prospects, add a case statement
ss.siteURN,
ss.sitedesc,
ss.FS_URL + 'frmcustomer.aspx?CustomerID=' + customerid as CustomerLink,
co.HomeCurrencyCode,
c.customerid,
c.currencycode,
c.entityname,
c.entityshortname,
c.address,
c.city,
c.postalcode,
c.countrycode,
cn.countryname,
c.statecode,
s.statename,
c.phone,
c.fax,
c.taxcode,
c.prospectid,
c.createdate,
c.lastupdatedate
from country cn,
SECSite ss,
company co,
customer c
left outer join state s
on c.statecode = s.statecode
where ss.LocalSiteFlag = 1
and cn.countrycode = c.countrycode
and not exists(select * from SEC_ODS.dbo.ODSCustomerBase b
where(Recordsource=b.Recordsource and
RecordType=b.RecordType and
ss.siteURN=b.siteURN and
ss.sitedesc=b.sitedesc and
ss.FS_URL=b.CustomerLink and
co.HomeCurrencyCode=b.HomeCurrencyCode and
c.customerid=b.customerid and
c.currencycode=b.CustomerCurrencyCode and
c.entityname=b.CustomerName and
c.entityshortname=b.CustomerShortName and
c.address=b.address and
c.city=b.city and
c.postalcode=b.postalcode and
c.countrycode=b.countrycode and
cn.countryname=b.countryname and
c.statecode=b.statecode and
s.statename=b.statename and
c.phone=b.phone and
c.fax=b.fax and
c.taxcode=b.taxcode and
c.prospectid=b.prospectid and
c.createdate=b.createdate and
c.lastupdatedate=b.lastupdatedate))
So if I check the ODS table using this script, it gives me 8790 results which is wrong.
use sec_ods
go
select count(*) from ODSCustomerBase
Can someone help me with this please?
Thank you.
Use either ISNULL or COALESCE around all the fields that could be NULL.
e.g. ISNULL(c.address,'') = ISNULL(b.address,'')
If you want to restrict the already inserted data better to go Merge Statment it will just update the existing data or insert the new data
MERGE ODSCustomerBase AS T
USING (
SELECT Col1,col2,.... FROM ODSCustomerBase
) AS S
ON (
t.Col1 = s.Col1
AND t.Col2 = s.Col2
AND .....
)
WHEN NOT MATCHED BY TARGET
THEN
INSERT (
Col1
,Col2
,....
,....
)
VALUES (
S.Col1
--,S.NrID
,s.Col2
,s.Col3
)
WHEN MATCHED
THEN
UPDATE
SET T.Col1 = S.Col1
WHEN NOT MATCHED BY SOURCE
AND EXISTS (
SELECT 1
FROM ODSCustomerBase c
WHERE t.Col1 = Col1
)
THEN
DELETE;

Retrieve records through inner join

I have a schema as per the below:
CREATE TABLE rruser (
id NUMBER(32,0) NOT NULL,
name VARCHAR2(30) NOT NULL,
fullname VARCHAR2(100) NOT NULL,
active_flag CHAR(1) DEFAULT 'N' NOT NULL
)
CREATE TABLE rruser_group (
user_id NUMBER(32,0) NOT NULL,
group_id NUMBER(32,0) NOT NULL
)
CREATE TABLE rrgroup (
id NUMBER(32,0) NOT NULL,
name VARCHAR2(100) NOT NULL,
code VARCHAR2(20) NOT NULL
)
CREATE TABLE rrgroup_permission (
group_id NUMBER(32,0) NOT NULL,
permission_id NUMBER(32,0) NOT NULL
)
CREATE TABLE rrpermission (
id NUMBER(32,0) NOT NULL,
name VARCHAR2(100) NOT NULL,
description VARCHAR2(1000) NOT NULL
)
The connectivity is such that RRUSER is linked to RRGROUP via table RRUSER_GROUP
and RRGROUP further linked with RRPERMISSION via table RRGROUP_PERMISSION.
I have to find out the users whose active flag value is equal to 'Y' within RRUSER; I'm using the below query
SELECT * FROM rruser WHERE ACTIVE_FLAG = 'Y'
I then have to find out the users which have write permission; in the last table, RRPERMISSION, there is a column NAME, which has the write permissions where the value of this column is 'write'. What query could I use to get this information? I know it should be achieved using an INNER JOIN.
Right now, I have tried a query for particular user to know whether he has write permission or not and have found out that he has write permission like this...
SELECT count(ID) FROM rruser WHERE ACTIVE_FLAG = 'Y';
SELECT * FROM rruser WHERE ACTIVE_FLAG = 'Y' AND FULLNAME = 'sss'
SELECT * FROM rruser_group WHERE USER_ID = 1100
SELECT * FROM rrgroup WHERE ID = 113;
SELECT * FROM rrgroup_permission WHERE GROUP_ID = 189 ;
SELECT * FROM rrpermission WHERE ID = 990
Try this:
SELECT ru.* FROM rruser ru
inner join rruser_group rg ON ru.id = rg.user_id
inner join rrgroup_permission rgp ON rg.group_id = rgp.group_id
inner join rrpermission rp ON rgp.permission_id = rp.id WHERE ru.ACTIVE_FLAG='Y' AND rp.name='write'

How to INSERT using an inverse JOIN on multiple keys?

How do I do an inverse join with more than one key column?
In this baby-toy SqlServer example, I have the following
CREATE TABLE [dbo].[CarList](
[myID] [int] IDENTITY(1,1) NOT NULL,
[CarColour] [varchar](32) NOT NULL,
[CarName] [varchar](128) NOT NULL,
[CarCompany] [varchar](32) NOT NULL,
CONSTRAINT [PK_CarList] PRIMARY KEY CLUSTERED(
[myID] ASC,
[CarColour] ASC,
[CarName] ASC,
[CarCompany] ASC
)
)
GO
INSERT INTO CarList (CarColour, CarName, CarCompany)
VALUES('blue', 'Abe', 'Ford')
Elsewhere in the DB I have a table like
CREATE TABLE [dbo].[NewCars](
[CarColour] [varchar](32) NOT NULL,
[CarName] [varchar](128) NOT NULL,
[CarCompany] [varchar](32) NOT NULL,
)
GO
INSERT INTO NewCars (CarColour, CarName, CarCompany)
SELECT 'blue', 'Abe', 'Ford'
UNION ALL
SELECT 'blue', 'Abe', 'GM'
UNION ALL
SELECT 'blue', 'Betty', 'Ford'
UNION ALL
SELECT 'green', 'Abe', 'Honda'
Now I want to insert cars I don't already have in the CarList table
Something like...
INSERT INTO CarList ( CarColour, CarName, CarCompany)
SELECT DISTINCT new.CarColour, new.CarName, new.CarCompany
FROM NewCars new, CarList old
WHERE new.CarColour <> old.CarColour
AND new.CarName <> old.CarName
AND new.CarCompany <> old.CarCompany
Which doesn't work because the "blue', 'Betty', 'Ford' row will get filtered out...
If this were just a single ID of some kind it would be really easy
INSERT INTO myTable (myID, param1, param2, etc)
SELECT param1, param2, etc
FROM someOtherTable new
WHERE new.myID NOT IN (SELECT myID FROM myTable)
For reasons I don't really want to get into, I cannot remove rows from NewCars that match CarList. I also need to do this in one pass if possible.
[edit]
Thanks guys!
thanks for DDL and DML
Here is one way
INSERT INTO CarList ( CarColour, CarName, CarCompany)
SELECT DISTINCT *
FROM NewCars n
where not exists (select 1 from CarList c where c.CarColour =n.CarColour
and c.CarName = n.CarName
and c.CarCompany = n.CarCompany)
There are at least 4 different way to do this
NOT IN (will not work for more than 1 column like you have)
NOT EXISTS
LEFT and RIGHT JOIN
OUTER APPLY (2005+)
EXCEPT (2005+)
Read Select all rows from one table that don't exist in another table
INSERT
INTO CarList ( CarColour, CarName, CarCompany)
SELECT CarColour, CarName, CarCompany
FROM NewCars nc
WHERE NOT EXISTS
(
SELECT 1
FROM CarList cl
WHERE cl.CarColor = nc.CarColor
AND cl.CarName = nc.CarName
AND cl.CarCompany = nc.CarCompany
)
I would probably use:
INSERT INTO CarList(CarColour, CarName, CarCompany)
SELECT
NC.CarColour,
NC.CarName,
NC.CarCompany
FROM
NewCars NC
LEFT OUTER JOIN CarList CL ON
CL.CarColour = NC.CarColour AND
CL.CarName = NC.CarName AND
CL.CarCompany = NC.CarCompany
WHERE
CL.MyID IS NULL
INSERT INTO CarList ( CarColour, CarName, CarCompany)
SELECT DISTINCT new.CarColor, new.CarName, new.CarCompany
FROM NewCar new
where not exists (select 0
from CarList old
WHERE new.CarColour = old.CarColour
AND new.CarName = old.CarName
AND new.CarCompany = old.CarCompany)
--This statement matches all that does exists in carlist
--and insert everything that does not exists in Carlist