Hi I'd like to know how to make that "iif" work.
Basically, I need to filter the engineering "product codes" when originator is "John Smith". currentmember is not working or that iif is not working,
SELECT
{
(
[Time].[Fiscal Hierarchy Time Calculations].[Month to Date],
[Measures].[Sell - Bookings]
)
} ON COLUMNS,
[Originators].[Originator One Letter Name].Children ON ROWS
FROM [Sales]
WHERE
(
[Time].[Fiscal Month].&[2010-02-01T00:00:00],
IIF
(
[Originators].[Originator One Letter Name].CurrentMember = "John Smith",
Except
(
[Product Codes].[Product Primary Subcategory].Children,
[Product Codes].[Product Primary Subcategory].&[ENGINEERING]
),
[Product Codes].[Product Primary Subcategory].Children
)
);
Any ideas?
Thanks in advance.
Duy
The best way to compare members in MDX is to use IS:
SELECT
{
(
[Time].[Fiscal Hierarchy Time Calculations].[Month to Date],
[Measures].[Sell - Bookings]
)
} ON COLUMNS,
[Originators].[Originator One Letter Name].Children ON ROWS
FROM [Sales]
WHERE
(
[Time].[Fiscal Month].&[2010-02-01T00:00:00],
IIF
(
[Originators].[Originator One Letter Name].CurrentMember IS
[Originators].[Originator One Letter Name].[JOHN SMITH],
Except
(
[Product Codes].[Product Primary Subcategory].Children,
[Product Codes].[Product Primary Subcategory].&[ENGINEERING]
),
[Product Codes].[Product Primary Subcategory].Children
)
);
Of course, you would have to change [Originators].[Originator One Letter Name].[JOHN SMITH] for the proper unique name of the member
Related
I have 3 tables, Company, Address and C_detail. I need to count how many company with a certain C_ID from the C_detail table. But the relation existed are Company(CompanyID)=Address(CompanyID), Address(CountryID)=C_detail(CountryID). To be exact I need to translate this sql into Power BI.
SELECT COUNT (*)
FROM Company a
JOIN Address b ON a.CompanyID = b.CompanyID
WHERE b.CountryID IN ( SELECT CountryID from C_detail WHERE C_ID = '1')
How I join the tables with applying condition from different table?
Thanks and note that I am actually quite new with DAX so really appreciate a very clear explanation on this.
The best way is to create the relationships between those 3 tables in powerBI (set the filter to both directions):
Company to Address on CompanyID
Address to C_detail on CountryID
Then you can create a simple measure COUNT(Company[CompanyID]) and use a slicer with the values of C_ID
If you don't want to or can't create the relationships, you can probably achieve a similar result with the following measure:
CompanyCount=
VAR tbl =
SELECTCOLUMNS (
FILTER (
SUMMARIZE (
'Address',
'Address'[CompanyID],
"valid",
CALCULATE (
COUNTROWS ( 'Address' ),
TREATAS ( VALUES ( 'Detail'[CountryID] ), 'Address'[CountryID] )
)
),
[valid] > 0
),
"CompanyID", 'Address'[CompanyID]
)
RETURN
CALCULATE ( COUNTROWS ( 'Company' ), TREATAS ( tbl, 'Company'[CompanyID] ) )
I have the following table structure :
I would like to be able to delete from the table the duplicated mails, leaving for each mail account only the one with the highest quality score. At the moment I have come up with the following SQL code :
DELETE *
FROM Table
WHERE ( Table.[Email Adress] & Table.[Quality Score] ) NOT IN
(
SELECT (Table.[Email Adress] & Max(Table.[Quality Score])
FROM Table
GROUP BY Table.[Email Adress]
);
However when I run it, it asks me for a parameter value and clearly doesn't work as I intended.
Do you have any solution?
You can simplify your query to this:
DELETE FROM Table AS t
WHERE t.[Quality Score] <> (
SELECT Max([Quality Score])
FROM Table
WHERE [Email Adress] = t.[Email Adress]
);
No need to GROUP BY [Email Adress] but you need a WHERE clause.
Or with EXISTS:
DELETE FROM Table AS t
WHERE EXISTS (
SELECT 1 FROM Table
WHERE [Email Adress] = t.[Email Adress] AND [Quality Score] > t.[Quality Score]
);
In case there are duplicate scores then you can keep the row with the highest score and the lowest id like this:
DELETE FROM Table AS t
WHERE EXISTS (
SELECT 1 FROM Table
WHERE [Email Adress] = t.[Email Adress]
AND ([Quality Score] > t.[Quality Score] OR ([Quality Score] = t.[Quality Score] AND id < t.id))
);
One method uses a correlated subquery:
delete from t
where t.quality_score < (select max(t2.quality_score)
from t as t2
where t2.email_address = t.email_address
);
Note: If you have duplicate highest scores, this keeps all of them. To address, you can use the id column:
delete from t
where t.id <> (select top 1 t2.id
from t as t2
where t2.email_address = t.email_address
order by t2.quality_score desc, id
);
I'm looking for a way to save some calculation from being done twice in a query like:
SELECT DISTINCT
coins.price_btc,
coins.price_eur,
coins.price_usd,
coins.currency_name,
coins.currency_symbol,
SUM ( market_transactions.quantity ) OVER ( PARTITION BY market_transactions.market_coin_id ) * coins.price_eur AS holdings_eur,
SUM ( market_transactions.quantity ) OVER ( PARTITION BY market_transactions.market_coin_id ) * coins.price_usd AS holdings_usd,
SUM ( market_transactions.quantity ) OVER ( PARTITION BY market_transactions.market_coin_id ) * coins.price_btc AS holdings_btc,
SUM ( market_transactions.quantity ) OVER ( PARTITION BY market_transactions.market_coin_id ) AS holdings
FROM
market_transactions
INNER JOIN coins ON coins.id = market_transactions.market_coin_id
WHERE
market_transactions.user_id = 1
ORDER BY
coins.currency_symbol
I'm not sure if that sum over partition is running all these times.
Thanks for any pointers, I'm sure the query can also be optimized but I'm unsure where to start.
CREATE TABLE "public"."coins" (
"id" int8 NOT NULL DEFAULT nextval('coins_id_seq'::regclass),
"currency_symbol" text COLLATE "pg_catalog"."default" NOT NULL DEFAULT NULL,
"currency_name" text COLLATE "pg_catalog"."default" NOT NULL DEFAULT NULL,
"price_usd" numeric(16,7) NOT NULL DEFAULT NULL,
"price_eur" numeric(16,7) NOT NULL DEFAULT NULL,
"price_btc" numeric(16,7) NOT NULL DEFAULT NULL,
CONSTRAINT "coins_pkey" PRIMARY KEY ("id")
)
CREATE TABLE "public"."market_transactions" (
"id" int8 NOT NULL DEFAULT nextval('market_transactions_id_seq'::regclass),
"user_id" int4 NOT NULL DEFAULT NULL,
"quantity" numeric(18,8) NOT NULL DEFAULT NULL,
"market_coin_id" int4 DEFAULT NULL,
CONSTRAINT "market_transactions_pkey" PRIMARY KEY ("id")
)
A user has many transactions involving a coin (market_transactions.market_coin_id is coins.id), I'm trying to SUM the quantity owned (market_transactions.quantity) for each one and then multiply this value for the price of the coin expressed in different currencies (btc, eur, usd)
I would suggest aggregating before joining and doing:
SELECT c.*,
mt.quantity * c.price_eur AS holdings_eur,
mt.quantity * c.price_usd AS holdings_usd,
mt.quantity * c.price_btc AS holdings_btc,
mt.quantity * c.market_coin_id AS holdings
FROM coins c JOIN
(SELECT mt.market_coin_id, SUM(mt.quantity) as quantity
FROM market_transactions t
WHERE mt.user_id = 1
GROUP BY mt.market_coin_id
) mt
ON c.id = mt.market_coin_id
ORDER BY c.currency_symbol
Run an EXPLAIN (i.e. EXPLAIN SELECT DISTINCT ...) on the query and see what the query plan is. Most likely, it's only running the window function once. If it is running it multiple times, try adding an outer SELECT:
SELECT DISTINCT
price_btc,
price_eur,
price_usd,
currency_name,
currency_symbol,
holdings * price_eur AS holdings_eur,
holdings * price_usd AS holdings_usd,
holdings * price_btc AS holdings_btc,
holdings
FROM (
SELECT
coins.price_btc,
coins.price_eur,
coins.price_usd,
coins.currency_name,
coins.currency_symbol,
SUM ( market_transactions.quantity ) OVER ( PARTITION BY market_transactions.market_coin_id ) AS holdings
FROM
market_transactions
INNER JOIN coins ON coins.id = market_transactions.market_coin_id
WHERE
market_transactions.user_id = 1
) src
ORDER BY
currency_symbol
So, I'm doing homework and the question is asking me the following
A representative from Northwind Traders will be in Germany. Management would like her to visit all German suppliers and customers while she is there. Provide a list of all suppliers and customers in Germany, including contacts and addresses. Designate on the report whether the company listed is a customer or a supplier.
The last part is what I am having trouble with, displaying if a company is a customer or supplier.
The set equivalent of logical OR is UNION e.g.
{ 1, 2, 3 } UNION { 2, 3, 4 } = { 1, 2, 3, 4 }
The relational model (RM) equivalent of logical OR is also UNION. All RM operators, the objects being operated on must be relations - google First Normal Form (1NF) for a formal definition. Additionally, UNION requires the two relations to be equivalent i.e. their set of attributes must be the same (by type and name); often the RENAME operator is required to satisfy this requirement e.g.
Suppliers ( SupplierName ) UNION Customers ( CustomerName )
wouldn't be valid but can be made valid using RENAME e.g.
( ( Suppliers RENAME ( SupplierName AS Name ) ) ( Name ) )
UNION
( ( Customers RENAME ( CustomerName AS Name ) ) ( Name ) )
If you need to retain the information about whether a name relates to a supplier or a customer then you can add a literal value e.g.
( ( Suppliers RENAME ( SupplierName AS Name ) ) ( Name, 'Supplier' AS Relationship ) )
UNION
( ( Customers RENAME ( CustomerName AS Name ) ) ( Name, 'Customer' AS Relationship ) )
Standard SQL supports all these operators but is much more strict about structure e.g. the attrributes must be projected in the same order. The equivalent of the last query:
SELECT SupplierName AS Name, 'Supplier' AS Relationship
FROM Suppliers
UNION
SELECT CustomerName AS Name, 'Customer' AS Relationship
FROM Customers
After poring over a similar problem and finding it never provided a complete solution I finally have gotten to the heart of the problem I can't solve. I'm looking for the consecutive amount of days that a person can be prescribed a certain amount of drugs. Because the prescriptions begin and end, there can be multiple, non-contiguous intervals that a person is on X number of drugs. The following SQL script produces the result set of the query I'll post momentarily: Also, I don't have SQL Server 2012.
create table test
(pat_id int, cal_date date, grp_nbr int, drug_qty int,[ranking] int)
go
insert into test(pat_id,cal_date, grp_nbr,drug_qty,[ranking])
values
(1, '1/8/2007',7,2, 1),
(1, '1/9/2007',7,2, 1),
(1, '1/10/2007',7, 2,1),
(1, '1/11/2007',7, 2,1),
(1, '1/12/2007',7, 2,1),
(1, '1/13/2007',7, 2,1),
(1, '1/14/2007',7, 2,1),
(1, '1/15/2007',7, 2,1),
(1, '6/1/2007',7,2, 1),
(1, '6/2/2007',7,2, 1),
(1, '6/3/2007',7,2, 1)
Notice here that there are two non-contiguous intervals where this person was on two drugs at once. In the days that are omitted,drug_qty was more than two. The last column in this example was my attempt at adding another field that I could group by to help solve the problem (didn't work).
Query to create tables:
CREATE TABLE [dbo].[rx](
[pat_id] [int] NOT NULL,
[fill_Date] [date] NOT NULL,
[script_End_Date] AS (dateadd(day,[dayssup],[filldate])),
[drug_Name] [varchar](50) NULL,
[days_Sup] [int] NOT NULL,
[quantity] [float] NOT NULL,
[drug_Class] [char](3) NOT NULL,
CHECK(fill_Date <=script_End_Date
PRIMARY KEY CLUSTERED
(
[clmid] ASC
)
CREATE TABLE [dbo].[Calendar](
[cal_date] [date] PRIMARY KEY,
[Year] AS YEAR(cal_date) PERSISTED,
[Month] AS MONTH(cal_date) PERSISTED,
[Day] AS DAY(cal_date) PERSISTED,
[julian_seq] AS 1+DATEDIFF(DD, CONVERT(DATE, CONVERT(varchar,YEAR(cal_date))+'0101'),cal_date),
id int identity);
the query I'm using to produce my result sets:
;WITH x
AS (SELECT rx.pat_id,
c.cal_date,
Count(DISTINCT rx.drug_name) AS distinctDrugs
FROM rx,
calendar AS c
WHERE c.cal_date BETWEEN rx.fill_date AND rx.script_end_date
AND rx.ofinterest = 1
GROUP BY rx.pat_id,
c.cal_date
--the query example I used having count(1) =2, but to illustrate the non-contiguous intervals, in practice I need the below having statement
HAVING Count(*) > 1),
y
AS (SELECT x.pat_id,
x.cal_date
--c2.id is the row number in the calendar table.
,
c2.id - Row_number()
OVER(
partition BY x.pat_id
ORDER BY x.cal_date) AS grp_nbr,
distinctdrugs
FROM x,
calendar AS c2
WHERE c2.cal_date = x.cal_date)
SELECT *,
Rank()
OVER(
partition BY pat_id, grp_nbr
ORDER BY distinctdrugs) AS [ranking]
FROM y
WHERE y.pat_id = 1604012867
AND distinctdrugs = 2
Besides the fact that I shouldn't have a column in the calendar table named 'id', is there anything egregiously wrong with this approach? I can get the query to show me the distinct intervals of distinctDrugs=x, but it will only work for that integer and not anything >1. By this I mean that I can find the separate intervals where a patient is on two drugs, but only when I use =2 in the having clause, not >1. I can't do something like
SELECT pat_id,
Min(cal_date),
Max(cal_date),
distinctdrugs
FROM y
GROUP BY pat_id,
grp_nbr
because this will pick up that second group of non-contiguous dates. Does anyone know of an elegant solution to this problem?
The key to this is a simple observation. If you have a sequence of dates, then the difference between them and an increasing sequence is constant. The following does this, assuming you are using SQL Server 2005 or greater:
select pat_id, MIN(cal_date), MAX(cal_date), MIN(drug_qty)
from (select t.*,
cast(cal_date as datetime) - ROW_NUMBER() over (partition by pat_id, drug_qty order by cal_date) as grouping
from #test t
) t
group by pat_id, grouping